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"
}
一切正常。根据响应结构,我们推断用户对象包含四个字段:id、name、age和address。
现在尝试创建新用户:
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. 总结
本文核心要点:
- 必须设置正确的Content-Type头,否则会触发415错误
- 客户端与服务端的媒体类型必须匹配
- 修改API时建议显式声明支持的格式,避免过度宽松
完整代码示例见GitHub仓库。