2. 背景故事

某老客户要求我们为其产品开发一个用户管理桌面应用。由于时间紧迫,我们决定复用他们现有的后端API。但踩坑的是这些API文档极其简陋,我们仅知道可用接口和请求方法,因此决定直接开发客户端应用对接这些API。

3. API请求测试

应用启动后先测试获取用户列表接口:

curl -X GET https://baeldung.service.com/user

成功返回数据。接着测试获取单个用户:

curl -X GET https://baeldung.service.com/user/{user-id}

响应如下:

{
    "id": 1,
    "name": "Jason",
    "age": 23,
    "address": "14th Street"
}

一切正常。根据响应结构,我们推断用户对象包含四个字段:idnameageaddress

现在尝试创建新用户:

curl -X POST -d '{"name":"Abdullah", "age":28, "address":"Apartment 2201"}' https://baeldung.service.com/user/

结果返回HTTP 415错误

{
    "timestamp": "yyyy-MM-ddThh:mm:ss.SSS+00:00",
    "status": 415,
    "error": "Unsupported Media Type",
    "path": "/user/"
}

在定位原因前,需要先理解这个错误码的含义

4. 415状态码解析

根据RFC 7231规范

415状态码表示服务器拒绝服务该请求,因为负载格式不被目标资源的方法支持。

简单说就是API不支持我们发送的数据格式。我们选择JSON格式是因为GET接口返回的是JSON,但这个假设导致踩坑

查看后端代码发现API定义:

@PostMapping(value = "/", consumes = {"application/xml"})
void AddUser(@RequestBody User user)

这明确说明API仅支持XML格式。这里consumes的作用是什么?

根据Spring官方文档

通过指定可消费的媒体类型缩小映射范围,要求请求的Content-Type头必须匹配其中一种类型。

5. 解决方案

5.1 将请求负载改为XML

最直接的方案是改用XML格式发送请求

curl -X POST -d '<user><name>Abdullah</name><age>28</age><address>Apartment 2201</address></user>' https://baeldung.service.com/user/

但依然报错。根据前文consumes的作用,我们漏掉了Content-Type头

curl -X POST -H "Content-Type: application/xml" -d '<user><name>Abdullah</name><age>28</age><address>Apartment 2201</address></user>' https://baeldung.service.com/user/

这次成功。但实际开发中可能遇到客户端无法生成XML的情况,这时需要修改服务端。

5.2 修改服务端API

假设客户允许我们修改后端,有三种方案可选

方案一:简单粗暴替换为JSON

@PostMapping(value = "/", consumes = {"application/json"}) 
void AddUser(@RequestBody User user)

JSON请求会成功,但会导致所有XML客户端报错

方案二:允许所有格式

@PostMapping(value = "/", consumes = {"*/*"}) 
void AddUser(@RequestBody User user)

虽然灵活,但过于宽松会导致代码库混乱

方案三:推荐方案 - 显式声明支持的格式

@PostMapping(value = "/", consumes = {"application/xml","application/json"}) 
void AddUser(@RequestBody User user)

这样既兼容现有XML客户端,又支持新JSON客户端。

6. 总结

本文核心要点:

  1. 必须设置正确的Content-Type头,否则会触发415错误
  2. 客户端与服务端的媒体类型必须匹配
  3. 修改API时建议显式声明支持的格式,避免过度宽松

完整代码示例见GitHub仓库


原始标题:415 Unsupported MediaType in Spring Application | Baeldung