为什么设置了Content-Type还是被后端拦截?
我在用 Vue 发送 POST 请求时,明明在 headers 里加了 Content-Type: application/json,但后端还是返回 400 错误,说 Content-Type 不合法。是我写法有问题吗?
试过直接用 axios.defaults.headers.common 设置,也试过在单个请求里单独配,都不行。后端同事说他们只接受标准的 JSON 类型,可我这看起来也没错啊……
<script>
import axios from 'axios';
export default {
methods: {
async submit() {
await axios.post('/api/login', {
username: 'test',
password: '123'
}, {
headers: {
'Content-Type': 'application/json'
}
});
}
}
}
</script>
先看下你现在的代码有什么问题:
1. 你传的请求数据是普通对象 {username: 'test', ...}
2. axios 会自作聪明地把它转成 FormData 格式
3. 虽然你设置了 Content-Type,但实际发送的数据格式和声明的不匹配
解决方案是手动把数据转成 JSON 字符串。试试这样改:
原理说明:
1. JSON.stringify 把对象转为标准 JSON 字符串
2. axios 收到字符串后就不会自作主张转格式了
3. 这时候 Content-Type 和实际数据格式就完全匹配了
如果还不行,可能有其他干扰因素:
1. 检查是否有全局拦截器修改了请求
2. 用浏览器开发者工具确认实际发送的请求头
3. 后端可能还有额外的验证,比如 charset 参数
补充个小技巧:可以封装个 axios 实例统一处理:
这问题确实很烦人,axios 的默认行为有点太"智能"了,经常和后端期望的不一致。建议下次和后端联调时直接用开发者工具截图看原始请求,比口头描述更准确。
axios 在你没显式指定
data类型时,会自动把对象序列化成 JSON,同时默认设置Content-Type为application/json。但如果你手动写了
headers: { 'Content-Type': 'application/json' },却没配data的序列化方式,或者后端对 Content-Type 的校验特别严格(比如要求必须是application/json而不是application/json;charset=utf-8),就容易出问题。更关键的是:你有没有检查浏览器开发者工具 Network 面板里,实际发出的请求头是不是真的就是
Content-Type: application/json?有时候中间件(比如 nginx、网关)会偷偷改头,或者你本地 devServer 有代理配置覆盖了请求头。
最稳妥的写法是:
不过其实更常见的坑是:你没传
data,或者传了但被 axios 默认序列化成application/x-www-form-urlencoded(比如你用了URLSearchParams或某些旧版 axios 行为),而你手动设了Content-Type: application/json却没改transformRequest,导致请求体是 form 格式,头却是 JSON —— 这种 mismatch 才是后端报 400 的主因。另外建议直接用
axios.post('/api/login', { username: 'test', password: '123' })不加 headers,让 axios 自己处理,它默认就对,反而更稳。除非后端死活要求你手动写死这个头,才考虑上面的
transformRequest方案。—— 这种事我前两天刚踩过,axios 升级后默认序列化逻辑有点微妙变化,你最好确认下请求体和头是不是对得上。