Spring Boot 3.2.1迁移后Content-Type异常:Web服务控制器消费/生产错误
迁移背景
将Spring Boot Web服务从2.4.5版本迁移至3.2.1版本后,原CRUD接口出现两类Content-Type处理异常:
问题1:POST/PUT请求异常
Servlet层自动将传入的Content-Type: application/json修改为Content-Type: application/json;charset=UTF-8,导致控制器方法无法匹配请求。即使显式在控制器方法上设置consumes="application/json;charset=UTF-8",问题仍未解决。
控制器POST方法示例:
@RequestMapping(value = "/voltagereading/", method = RequestMethod.POST, consumes = "application/json;charset=UTF-8", produces = MediaType.APPLICATION_JSON) public @ResponseBody VoltageReading createVoltageReading(@RequestBody final VoltageReading newReading) throws SQLException, Exception { // 方法实现 }
问题2:GET/DELETE请求异常
Servlet处理响应时错误地将Content-Type设为null,导致Jackson库无法找到对应的序列化转换器,无法将VoltageReading对象转为JSON。日志报错如下:
2024-01-17 10:09:33 ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/esp32service/api].[dispatcherServlet] Servlet.service() for servlet [dispatcherServlet] in context with path [/esp32service/api] threw exception [Request processing failed: org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class com.mdhlabs.esp32service.models.VoltageReading] with preset Content-Type 'null'] with root cause org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class com.mdhlabs.esp32service.models.VoltageReading] with preset Content-Type 'null'
VoltageReading类具备无参构造函数,未配置JSON注解(在2.4.5版本可正常序列化)。尝试修改application.properties编码配置无效:
server.servlet.encoding.charset=UTF-8 server.servlet.encoding.force-response=true
问题解答
1. Spring Boot 3.2.1及Spring Core 6.1.13是否需额外注解以保持原JSON处理逻辑?
不需要额外注解。Spring Boot 3.x基于Spring 6,默认仍用Jackson作为JSON处理器,只要实体类符合Jackson序列化要求(如有无参构造、字段可访问),就能正常序列化/反序列化。迁移后出现问题,大概率是编码或请求/响应处理的配置变更导致,而非注解缺失。
2. 能否阻止Spring Boot向Content-Type头追加charset=UTF-8?
可以,有两种方式:
- 自定义Jackson消息转换器:创建配置类,调整MappingJackson2HttpMessageConverter的支持媒体类型,避免添加charset:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); converter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON)); converters.add(0, converter); } }
- 调整Servlet编码配置:设置
server.servlet.encoding.force=false,这样不会强制修改请求的Content-Type,但注意这会影响所有Servlet层面的编码处理,需根据场景权衡。
3. 为何显式配置application/json;charset=UTF-8仍无法匹配请求?
Spring MVC匹配consumes属性时会严格校验媒体类型的所有参数(包括charset),可能存在以下问题:
- Servlet层修改后的Content-Type存在大小写、参数顺序差异;
- 请求实际传入的Content-Type与配置仍不匹配;
- 存在其他过滤器/拦截器修改请求头,导致最终到达控制器的Content-Type不符合预期。
更稳妥的方式是直接使用MediaType.APPLICATION_JSON_VALUE作为consumes值,它会自动匹配带或不带charset的application/json类型:
@RequestMapping(value = "/voltagereading/", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
4. 响应序列化时Content-Type为null的原因是什么?DAO已返回可序列化对象。
可能的原因包括:
- 自定义拦截器/过滤器在处理响应时意外清空了Content-Type头;
- 消息转换器配置异常,导致Spring无法确定响应媒体类型;
- 仍在使用
@Controller+@ResponseBody的老旧组合,Spring Boot 3.x推荐使用@RestController替代,确保响应处理逻辑正确; - 存在异常处理器或全局响应拦截器,干扰了响应头的设置。
建议先将控制器类改为@RestController并移除方法上的@ResponseBody,再排查是否有自定义Web组件修改响应头。若问题仍存在,可调试MappingJackson2HttpMessageConverter的write方法,查看Content-Type的设置过程。
内容的提问来源于stack exchange,提问作者mdhlabs

