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

這篇幫到你了嗎?

剛解決了一個棘手的報錯?花兩分鐘記錄下來,幫助下一個遇到同樣問題的開發者。

貢獻一條解法