报错信息:Exception in thread "[T]dc3-thread-4" java.lang.RuntimeException: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('A' (code 65)): Expected space separating root-level values at [Source: (String)"2A0611A49323"; line: 1, column: 3]
这个报错的意思是 Jackson 解析的内容不是「合法 JSON 格式」:目标字符串 2A0611A49323 被当作 JSON 解析,但不符合 JSON 语法规则,导致解析失败。具体原因和解决方案如下:
一、报错根源拆解
1. JSON 语法规则冲突
Jackson 是 JSON 序列化框架,仅能解析 标准 JSON 格式。而报错中的源数据 2A0611A49323 是「裸字符串」(无 JSON 语法包裹),违反以下规则:
- JSON 中字符串必须用 双引号 包裹(如
"2A0611A49323"),不能直接写裸字符串(2A0611A49323); - 报错中
line: 1, column: 3指向字符A(第 3 个字符):Jackson 解析到2A时,认为2是数字开头,但后续A不是数字 / 空格,不符合 JSON 根级值的语法(JSON 根级只能是对象{}、数组[]、字符串"xxx"、数字、布尔、null)。
2. 常见场景(按概率排序)
- 场景 1:前端 / 上游服务传递的是「裸字符串」(如
2A0611A49323),但后端用@RequestBody(默认按 JSON 解析)接收; - 场景 2:传递的字符串包含特殊字符(如
2A"0611A49323含未转义的双引号),导致 JSON 语法错乱; - 场景 3:后端误将「非 JSON 数据」(如十六进制字符串、普通文本)交给 Jackson 解析(如用
ObjectMapper.readValue()解析裸字符串)。
二、解决方案(按场景分类)
场景 1:后端需接收「单个字符串」(最常见)
若业务中 2A0611A49323 是单个字符串(如设备编号、令牌),需让 Jackson 正确解析「JSON 格式的字符串」,或绕过 JSON 解析直接接收裸字符串。
方案 1:前端传递「标准 JSON 字符串」(推荐)
让前端将裸字符串用 双引号包裹,转为合法 JSON 格式(如 "2A0611A49323"),后端正常用 String 接收。
- 前端示例(Axios)
// 错误:传递裸字符串(非 JSON) axios.post("/api/device", "2A0611A49323"); // 正确:传递 JSON 格式字符串(双引号包裹) axios.post("/api/device", JSON.stringify("2A0611A49323")); // 或直接写 JSON 字符串(注意外层双引号+内层转义,避免语法错误) axios.post("/api/device", "\"2A0611A49323\""); - 后端示例(Spring Boot):
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController public class DeviceController { // 直接用 String 接收 JSON 格式的字符串 @PostMapping("/api/device") public String receiveDeviceId(@RequestBody String deviceId) { System.out.println(deviceId); // 输出:2A0611A49323(自动去掉 JSON 外层双引号) return "success"; } }
方案 2:后端绕过 JSON 解析,直接接收裸字符串
若前端无法修改(如第三方服务推送),后端将接收方式改为 @RequestParam(Query 参数)或 @PathVariable(路径参数),避免 Jackson 解析 JSON:
- 示例 1:Query 参数(推荐,无侵入)
// 前端请求:/api/device?deviceId=2A0611A49323 @PostMapping("/api/device") public String receiveDeviceId(@RequestParam String deviceId) { System.out.println(deviceId); // 输出:2A0611A49323(直接接收裸字符串) return "success"; } - 示例 2:路径参数(适用于短字符串)
// 前端请求:/api/device/2A0611A49323 @PostMapping("/api/device/{deviceId}") public String receiveDeviceId(@PathVariable String deviceId) { return "success"; }
方案 3:配置 Jackson 允许「非标准 JSON 字符串」(不推荐,仅临时兼容)
通过 Jackson 配置允许解析裸字符串(可能引发其他 JSON 解析问题,谨慎使用):
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
// 允许解析裸字符串(无双引号包裹的字符串)
objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return objectMapper;
}
}
场景 2:传递的字符串包含特殊字符(如未转义的双引号)
若字符串本身含特殊字符(如 2A"0611A49323),需前端转义特殊字符后再按 JSON 传递:
- 前端转义示例(JavaScript):
const deviceId = '2A"0611A49323'; // 含未转义的双引号 const jsonStr = JSON.stringify(deviceId); // 自动转义:"2A\"0611A49323" axios.post("/api/device", jsonStr); - 后端接收后会自动反转义,无需额外处理:
@PostMapping("/api/device") public String receiveDeviceId(@RequestBody String deviceId) { System.out.println(deviceId); // 输出:2A"0611A49323(自动反转义) return "success"; }
场景 3:后端手动调用 Jackson 解析裸字符串(代码层面问题)
若报错来自后端代码中手动调用 ObjectMapper.readValue() 解析裸字符串(如下),需补充 JSON 格式包裹:
- 错误写法(解析裸字符串):
String rawStr = "2A0611A49323"; // 裸字符串 ObjectMapper objectMapper = new ObjectMapper(); String deviceId = objectMapper.readValue(rawStr, String.class); // 报错! - 正确写法(手动添加 JSON 双引号):
String rawStr = "2A0611A49323"; String jsonStr = "\"" + rawStr + "\""; // 转为 JSON 格式字符串:"2A0611A49323" String deviceId = objectMapper.readValue(jsonStr, String.class); // 成功解析
三、关键验证步骤
-
确认传递的数据格式:
- 用 Postman/F12 网络面板抓包,查看请求体(Request Body)是否为
2A0611A49323(裸字符串),若是则按场景 1 修复; - 若请求体是
{"deviceId": "2A0611A49323"}(JSON 对象),则后端需定义对应的 DTO 接收(而非直接用 String):public class DeviceDTO { private String deviceId; // getter/setter } @PostMapping("/api/device") public String receiveDevice(@RequestBody DeviceDTO dto) { System.out.println(dto.getDeviceId()); // 输出:2A0611A49323 return "success"; }
- 用 Postman/F12 网络面板抓包,查看请求体(Request Body)是否为
-
排查特殊字符:
- 若字符串含
\、"、'等特殊字符,按场景 2 转义后传递; - 用工具验证 JSON 合法性:将请求体粘贴到 JSON.cn,若提示 “语法错误”,则说明格式不合法。
- 若字符串含
四、总结
这个报错的本质是「数据格式与解析方式不匹配」:Jackson 期望解析 JSON,但实际接收的是裸字符串 / 非法 JSON。优先解决方案是 让前端传递标准 JSON 格式字符串(双引号包裹),或后端改用 @RequestParam/@PathVariable 直接接收裸字符串,避免 JSON 解析冲突。
按以上步骤修复后,Jackson 能正常解析,报错会消失
1575

被折叠的 条评论
为什么被折叠?



