StackTraces
Spring Boot已验证

Spring Boot 报 HttpMessageNotWritableException

@debug_master32 天前更新阅读 6 min00

这个异常的含义就一句话:Spring 找不到能把这个 Java 对象写进响应的 HttpMessageConverter。要么你 produces 指定了一个没配转换器的媒体类型,要么返回类型写得像 Object 那样宽,让 Spring 没法推断。

Issue & Env(案发现场与环境)

  • 现象:控制器方法执行正常,但返回结果阶段抛 500,客户端拿不到数据。
  • 环境:Spring Boot 2.x / 3.x,spring-boot-starter-web(默认带 Jackson)。常见于指定了 XML 等非 JSON 输出、或改动了内容协商配置的场景。

StackTrace(堆栈日志)

服务端日志里的标准异常:

org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class com.example.Student] with preset Content-Type 'null'
	at org.springframework.http.converter.HttpMessageConverterConfigurer.chooseConverter(HttpMessageConverterConfigurer.java:157)
	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.writeWithMessageConverters(RequestResponseBodyMethodProcessor.java:195)
	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:182)
	at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:78)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeAdapterInternal(RequestMappingHandlerAdapter.java:398)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1043)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:1004)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:750)
Caused by: java.lang.IllegalArgumentException: 'resolver' must not be null
	at org.springframework.util.Assert.notNull(Assert.java:204)
	at org.springframework.http.converter.xml.Jaxb2CollectionHttpMessageConverter.writeTo(Jaxb2CollectionHttpMessageConverter.java:102)
	... 14 more

也有另一种写法(返回类型不明确时):

org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type: class com.example.Student
	at org.springframework.http.converter.HttpMessageConverterConfigurer.chooseConverter(HttpMessageConverterConfigurer.java:157)
	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.writeWithMessageConverters(RequestResponseBodyMethodProcessor.java:195)
	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:182)
	at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:78)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeAdapterInternal(RequestMappingHandlerAdapter.java:398)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1043)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:1004)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:750)
Caused by: java.lang.IllegalArgumentException: 'resolver' must not be null
	at org.springframework.util.Assert.notNull(Assert.java:204)
	at org.springframework.http.converter.xml.Jaxb2CollectionHttpMessageConverter.writeTo(Jaxb2CollectionHttpMessageConverter.java:102)
	... 14 more

这两种都是同一个根子:写响应时没找到合适的消息转换器。

Reproduce(复现代码)

用 produces 指定一个没注册转换器的媒体类型(比如 application/xml,但没加 XML 转换器):

@RestController
public class StudentController {

    @GetMapping(value = "/student", produces = MediaType.APPLICATION_XML_VALUE)
    public Student get() {
        return new Student(1, "Tom");
    }
}

Spring Boot 默认只带 Jackson JSON 转换器。启动后访问 /student,就抛上面那段异常。

Root Cause(根因分析)

Spring MVC 写响应体时,会根据返回值类型和请求的 Accept / produces 媒体类型,从注册好的 HttpMessageConverter 列表里挑一个能写的。挑不到,就抛 HttpMessageNotWritableException。

转换器是自动配置注册的:MappingJackson2HttpMessageConverter 只有在 classpath 里有 Jackson 时才会注册。你 produces = application/xml,但要写 XML 得额外引入 jackson-dataformat-xml(以及 STAX),否则一个能写 XML 的转换器都没有,内容协商直接落空。

还有一种隐蔽形态:控制器方法返回类型写成 Object,Spring 得在运行时靠真实对象类型去匹配转换器,一旦那个类型没有对应转换器,同样失败。spring-ai-ascend 的 issue #226 里就是这种情况——返回类型写 Object,某个 SDK 内部 POJO 没有转换器,Content-Type 被协商成 null。

The Fix(解决方案)

先确认你到底要输出什么格式。

输出 JSON,就把 produces 改成 JSON,或干脆去掉。有 Jackson 依赖时,MappingJackson2HttpMessageConverter 会自动兜底:

@GetMapping(value = "/student", produces = MediaType.APPLICATION_JSON_VALUE)
public Student get() {
    return new Student(1, "Tom");
}

真要输出 XML,补上依赖:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

返回类型尽量写具体,别用 Object。需要封装状态码和响应头时,用 ResponseEntity:

@GetMapping("/student")
public ResponseEntity<Student> get() {
    return ResponseEntity.ok(new Student(1, "Tom"));
}

具体返回类型加上 ResponseEntity,能让 Spring 在编译期就知道目标类型,减少运行时的内容协商歧义。

References(参考来源)

最后更新于 2026-09-09

这篇帮到你了吗?

刚解决了一个棘手的报错?花两分钟记录下来,帮助下一个遇到同样问题的开发者。

贡献一条解法