如何调试POST请求中的net::ERR_FAILED/415 Unsupported Media Type错误?
我来一步步帮你理清这些问题的原因和解决方向:
1. 为什么未设置自定义请求头时只有415错误,没有CORS报错?
当你不手动设置Content-Type时,axios默认会把POST请求的Content-Type设为application/x-www-form-urlencoded,这个请求属于CORS简单请求(满足:请求方法是GET/POST/HEAD、Content-Type是三种允许的简单类型之一、没有自定义请求头)。
对于简单请求,浏览器不会发送OPTIONS预检请求,直接发送POST请求到后端。后端收到请求后,发现Content-Type不符合API要求(Swagger显示需要的是其他格式),所以返回415 Unsupported Media Type错误。而这时候后端返回的响应头里应该已经包含了CORS允许的字段(比如Access-Control-Allow-Origin),所以浏览器不会触发CORS报错。
2. 为什么设置自定义请求头后,axios/fetch会发送OPTIONS而非POST?
当你设置了Content-Type: application/json-patch+json(或application/json),这个请求就不再是简单请求了——因为Content-Type不在简单请求允许的三种类型里。此时浏览器会先发送OPTIONS预检请求,用来询问后端:是否允许来自http://localhost:8081的跨域请求?是否允许使用POST方法?是否允许携带这个自定义的Content-Type头?
如果后端的CORS配置没有正确处理OPTIONS请求(比如返回404状态码,或者响应头里缺少必要的CORS字段),浏览器就会判定预检不通过,直接阻止后续的POST请求,同时抛出CORS错误。
至于Chrome和Vivaldi的显示差异:Chrome准确显示了预检的OPTIONS请求(因为POST根本没被发送出去),而Vivaldi可能把浏览器尝试发送POST但被拦截的过程显示为POST请求失败,本质上都是预检不通过导致的问题。
3. 为什么fetch也出现同样的问题?
这完全排除了axios的问题——不管用axios还是原生fetch,只要触发了非简单请求,都会走同样的CORS预检流程。你测试的两种fetch请求结果也验证了这一点:
- 不设置正确Content-Type时,属于简单请求,直接发送POST,后端返回415(格式不匹配)
- 设置正确Content-Type时,触发OPTIONS预检,预检不通过导致请求失败
下一步解决建议
你已经把资料发给后端了,建议和后端同事重点确认这几点:
- 明确API要求的Content-Type到底是
application/json-patch+json还是application/json,Swagger文档的描述要准确 - 检查后端的CORS配置是否正确处理OPTIONS请求:
- OPTIONS请求必须返回200或204状态码
- 响应头必须包含
Access-Control-Allow-Origin,要允许你的http://localhost:8081 - 响应头必须包含
Access-Control-Allow-Headers,要包含你使用的Content-Type值 - 响应头必须包含
Access-Control-Allow-Methods,要包含POST方法
- 可以让后端用Postman或curl手动发送OPTIONS请求到该API端点,检查返回的状态码和响应头是否符合要求
- 暂时可以先尝试用
Content-Type: application/json测试,有些后端对application/json-patch+json的支持需要额外配置,先确认基础JSON格式是否能被API接受
内容的提问来源于stack exchange,提问作者YakovL

