在 Spring Boot 中,使用 @RequestBody String 接收参数是一种常见但需要谨慎处理的场景。它主要用于直接获取 HTTP 请求体(Request Body)的原始字符串内容,而不是将其自动反序列化为 Java 对象。
- 原理
当控制器方法参数定义为 @RequestBody String text 时,Spring MVC 的处理流程如下:
消息转换器选择:Spring 会查找合适的 HttpMessageConverter。对于 String 类型,通常使用 StringHttpMessageConverter。
Content-Type 匹配:
如果请求头 Content-Type 为 text/plain,StringHttpMessageConverter 会直接读取流并转换为字符串。
如果请求头 Content-Type 为 application/json,Spring 可能会尝试使用 MappingJackson2HttpMessageConverter(如果配置了),或者仍然由 StringHttpMessageConverter 处理(取决于具体版本和配置)。通常情况下,即使 Content-Type 是 JSON,只要目标是 String,Spring 也能读取原始字节流转为字符串。
数据绑定:将读取到的原始字符序列直接赋值给参数变量,不进行任何 JSON 解析或对象映射。
- 使用场景
场景一:接收非结构化文本或自定义格式数据
当客户端发送的数据不是标准的 JSON 或 XML,而是纯文本、CSV、XML 字符串或其他自定义格式时,使用 String 接收最为灵活。
@PostMapping(value = "/receiveText", consumes = "text/plain")
public String handlePlainText(@RequestBody String body) {
// body 包含原始的文本内容
return "Received: " + body;
}
场景二:手动解析 JSON 或特殊逻辑处理
如果需要使用特定的 JSON 库(如 Fastjson、Gson)进行解析,或者需要在反序列化前对原始 JSON 字符串进行预处理(如解密、验签),可以先接收为 String。
@PostMapping("/manualJsonParse")
public ResponseEntity<?> handleRawJson(@RequestBody String jsonStr) {
try {
// 1. 验签或解密操作
String decrypted = decrypt(jsonStr);
// 2. 手动转换为对象 (以 Jackson 为例)
ObjectMapper mapper = new ObjectMapper();
MyDataDto data = mapper.readValue(decrypted, MyDataDto.class);
// 3. 业务处理
return ResponseEntity.ok("Success");
} catch (Exception e) {
return ResponseEntity.badRequest().body("Parse Error");
}
}
场景三:Webhook 或第三方回调验证
某些第三方服务(如微信支付、GitHub Webhook)会在请求头中携带签名,签名是基于原始请求体计算的。为了验证签名,你必须获取未经修改的原始 Body 字符串。
@PostMapping("/webhook")
public String verifyWebhook(@RequestBody String payload, @RequestHeader("X-Signature") String signature) {
// 使用原始 payload 计算签名并与 header 中的 signature 比对
if (verifySignature(payload, signature)) {
// 处理业务
return "success";
}
return "fail";
}
- 常见误区与避坑指南
误区 1:认为 @RequestBody String 会自动解析 JSON
错误理解:以为传入 {"name":"Alice"},String 变量会自动变成对象或提取出 name 字段。
事实:变量 text 的值将是完整的字符串 "{\"name\":\"Alice\"}"。你需要手动解析它。
误区 2:忽略 Content-Type 导致 415 错误
如果控制器方法没有明确指定 consumes,而客户端发送的 Content-Type 不被默认的 StringHttpMessageConverter 支持(某些旧版本可能仅严格支持 text/plain),可能会抛出 415 Unsupported Media Type。
解决:
在 @PostMapping 中指定 consumes = {"application/json", "text/plain"}。
或者确保客户端发送正确的 Header。
误区 3:与 @RequestParam 混淆
@RequestParam:从 URL 查询参数(Query Params)或表单数据(Form Data)中获取简单键值对。
@RequestBody:从 HTTP 请求体(Body)中获取数据,通常用于 POST/PUT 请求,适合复杂结构或大量数据。
误区 4:中文乱码问题
虽然 Spring Boot 默认配置了 CharacterEncodingFilter 为 UTF-8,但在某些特定服务器配置或旧版本中,直接接收 String 可能会出现乱码。
解决:确保项目全局编码设置为 UTF-8,或在 application.properties/yml 中配置:
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.force=true
- 代码示例对比
方式 A:自动反序列化(推荐用于标准 JSON)
@PostMapping("/user")
public User createUser(@RequestBody User user) {
// Spring 自动将 JSON 转为 User 对象
return userService.save(user);
}
方式 B:原始字符串接收(用于特殊处理)
@PostMapping("/user/raw")
public String createUserRaw(@RequestBody String jsonBody) {
// jsonBody 是原始字符串,如 "{\"name\":\"Alice\",\"age\":30}"
log.info("Raw JSON: {}", jsonBody);
// 手动处理...
return "Processed";
}
- 总结建议
|---------|---------------------|---------------------|
| 特性 | @RequestBody Object | @RequestBody String |
| 适用数据格式 | 标准 JSON/XML | 任意文本、JSON、XML、CSV |
| 处理方式 | 自动反序列化 | 原始字符串,需手动解析 |
| 便利性 | 高,直接操作对象 | 低,需额外解析步骤 |
| 灵活性 | 低,受限于类结构 | 高,可自定义解析逻辑 |
| 典型场景 | 常规 CRUD 接口 | 验签、加密数据、非标准格式 |
6、最佳实践:
除非有明确的理由需要操作原始字符串(如验签、自定义解析、兼容非 JSON 格式),否则优先推荐使用 @RequestBody 配合具体的 DTO 对象。这样能利用 Spring 的类型转换、校验(@Valid)和自动化优势,代码更简洁且易于维护。