1. 概述
本文将快速解析 Spring MVC 中的 HttpMediaTypeNotAcceptableException
异常,并分析在哪些场景下可能遇到这个异常。
2. 问题本质
使用 Spring 实现 API 接口时,我们通常需要通过 consumes
和 produces
参数指定接口能处理的媒体类型。这限制了该接口能返回给客户端的数据格式。
HTTP 协议中有个专门的 Accept
请求头,用于声明客户端可识别和接受的媒体类型。简单来说,服务器会优先使用客户端请求的媒体类型返回资源。
但当客户端和服务器之间没有共同支持的媒体类型时,Spring 就会抛出 HttpMediaTypeNotAcceptableException
异常。
3. 实际案例
下面通过一个简单示例来复现这个问题。
我们创建一个 POST 接口,它只处理 application/json
格式,并且也返回 JSON 数据:
@PostMapping(
value = "/test",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public Map<String, String> example() {
return Collections.singletonMap("key", "value");
}
现在用 CURL 发送一个请求,指定客户端接受 application/pdf
格式:
curl -X POST --header "Accept: application/pdf" http://localhost:8080/test -v
> POST /test HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.51.0
> Accept: application/pdf
服务器返回的响应:
< HTTP/1.1 406
< Content-Length: 0
4. 解决方案
解决这个问题的唯一方法就是:使用双方都支持的媒体类型进行请求/响应。
我们可以通过自定义 ExceptionHandler
提供更友好的错误提示(默认 Spring 返回空响应体),明确告知客户端所有可接受的媒体类型。
在我们的案例中,只支持 application/json
:
@ResponseBody
@ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
public String handleHttpMediaTypeNotAcceptableException() {
return "acceptable MIME type:" + MediaType.APPLICATION_JSON_VALUE;
}
5. 总结
本文分析了当客户端请求的媒体类型与服务器能产生的类型不匹配时,Spring MVC 抛出 HttpMediaTypeNotAcceptableException
的场景和解决方案。
本文所有代码示例可在 GitHub 仓库 中找到。