SpringBoot接口接收含单引号JSON请求报400错误的解决问询
解决SpringBoot中Jackson解析含单引号请求体的问题
首先,咱们来拆解你遇到的错误:JSON parse error: Unexpected end-of-input in VALUE_STRING,这个报错本质是Jackson在解析JSON时,把字符串里的单引号误判成了字符串的结束标记,导致解析到一半就认为字符串提前结束了。下面分两种常见场景给你解决方案:
场景1:请求体是合法JSON(双引号包裹字符串,内部含单引号)
如果你的请求体是标准JSON格式,比如{"name" : "peter o'toole"},这种情况下单引号属于字符串的合法内容,Jackson默认应该能正常解析。要是还是报错,先排查这几点:
- 确认请求头的
Content-Type是application/json,SpringBoot只会对这个类型的请求体用Jackson解析 - 用JSON校验工具(比如在线的JSON校验器)检查请求体格式是否完全合法,有没有遗漏逗号、括号这类细节
- 看看SpringBoot和Jackson的版本是否兼容,老旧版本可能存在解析bug
如果以上都没问题,你可以显式配置Jackson确保它允许字符串内部的单引号:
配置文件方式(application.properties)
# 开启宽松解析规则,避免因非核心格式问题报错 spring.jackson.deserialization.fail-on-unknown-properties=false spring.jackson.parser.allow-unquoted-control-chars=true
配置类方式
@Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); // 允许字符串中包含未转义的控制字符(包括单引号) objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true); return objectMapper; } }
场景2:请求体是非标准JSON(单引号包裹字符串/字段)
如果前端传的是非标准JSON,比如用单引号包裹字段或值:{'name' : 'peter o'toole'},这种格式本身不符合JSON规范,Jackson默认会拒绝解析。此时你可以配置Jackson允许单引号作为字符串分隔符,同时要求前端转义字符串内部的单引号(比如改成{'name' : 'peter o\'toole'})。
配置文件方式(application.properties)
# 允许用单引号代替双引号包裹字符串 spring.jackson.parser.allow-single-quotes=true # 允许字段名不带引号(如果前端有这种写法的话) spring.jackson.parser.allow-unquoted-field-names=true # 允许用反斜杠转义任意字符,包括单引号 spring.jackson.parser.allow-backslash-escaping-any-character=true
配置类方式
@Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); // 允许单引号包裹字符串 objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); // 允许字段名不带引号 objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); // 允许反斜杠转义任意字符 objectMapper.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true); return objectMapper; } }
极端临时方案:前端无法修改请求格式
如果前端完全没法调整请求格式,你可以通过自定义HttpMessageConverter预处理请求体,把非法的单引号转义或替换成双引号。但这种方式有风险,可能会破坏合法的JSON结构,只建议作为临时应急方法:
@Configuration public class CustomJacksonHttpMessageConverterConfig { @Bean public MappingJackson2HttpMessageConverter customMappingJackson2HttpMessageConverter() { MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); converter.setObjectMapper(objectMapper); // 自定义请求体预处理逻辑 converter.setRequestBodyConverter(new HttpMessageConverter<Object>() { @Override public boolean canRead(Class<?> clazz, MediaType mediaType) { return converter.canRead(clazz, mediaType); } @Override public Object read(Class<?> clazz, HttpInputMessage inputMessage) throws IOException { // 读取原始请求体 String rawBody = StreamUtils.copyToString(inputMessage.getBody(), StandardCharsets.UTF_8); // 替换字符串内部未转义的单引号(仅针对单引号包裹的字符串场景) String processedBody = rawBody.replaceAll("(?<!\\\\)'(?!([^']*'[^']*')*[^']*$)", "\\\\'"); // 重新构造输入流 ByteArrayInputStream inputStream = new ByteArrayInputStream(processedBody.getBytes(StandardCharsets.UTF_8)); HttpInputMessage newInputMessage = new HttpInputMessage() { @Override public InputStream getBody() throws IOException { return inputStream; } @Override public HttpHeaders getHeaders() { return inputMessage.getHeaders(); } }; return converter.read(clazz, newInputMessage); } // 其他方法默认实现即可 @Override public boolean canWrite(Class<?> clazz, MediaType mediaType) { return false; } @Override public List<MediaType> getSupportedMediaTypes() { return converter.getSupportedMediaTypes(); } @Override public void write(Object o, MediaType mediaType, HttpOutputMessage outputMessage) {} }); return converter; } }
提醒:这种自定义处理逻辑需要根据你的实际请求格式调整,否则可能引发新的解析问题,优先推荐前端修复JSON格式。
内容的提问来源于stack exchange,提问作者user2405589
相关产品推荐
相关产品推荐

