为什么设置了Content-Type还是被后端拦截?

UI硕辰 阅读 22

我在用 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>
我来解答 赞 2 收藏
二维码
手机扫码查看
2 条解答
开发者雨鑫
哈,这问题我遇到过不止一次了,八成是 axios 在背后搞的小动作。关键点在于 axios 默认会把请求数据转换成 URL 编码格式,即使你设置了 Content-Type 为 JSON。

先看下你现在的代码有什么问题:
1. 你传的请求数据是普通对象 {username: 'test', ...}
2. axios 会自作聪明地把它转成 FormData 格式
3. 虽然你设置了 Content-Type,但实际发送的数据格式和声明的不匹配

解决方案是手动把数据转成 JSON 字符串。试试这样改:


async submit() {
await axios.post('/api/login',
JSON.stringify({ // 关键在这里,手动序列化
username: 'test',
password: '123'
}),
{
headers: {
'Content-Type': 'application/json'
}
}
);
}


原理说明:
1. JSON.stringify 把对象转为标准 JSON 字符串
2. axios 收到字符串后就不会自作主张转格式了
3. 这时候 Content-Type 和实际数据格式就完全匹配了

如果还不行,可能有其他干扰因素:
1. 检查是否有全局拦截器修改了请求
2. 用浏览器开发者工具确认实际发送的请求头
3. 后端可能还有额外的验证,比如 charset 参数

补充个小技巧:可以封装个 axios 实例统一处理:

const api = axios.create({
transformRequest: [(data) => {
return typeof data === 'object'
? JSON.stringify(data)
: data;
}]
});


这问题确实很烦人,axios 的默认行为有点太"智能"了,经常和后端期望的不一致。建议下次和后端联调时直接用开发者工具截图看原始请求,比口头描述更准确。
点赞
2026-03-05 14:27
Mr.瑞红
Mr.瑞红 Lv1
你这个写法本身没问题,但问题出在 axios 的默认行为上。
axios 在你没显式指定 data 类型时,会自动把对象序列化成 JSON,同时默认设置 Content-Typeapplication/json
但如果你手动写了 headers: { 'Content-Type': 'application/json' },却没配 data 的序列化方式,或者后端对 Content-Type 的校验特别严格(比如要求必须是 application/json 而不是 application/json;charset=utf-8),就容易出问题。

更关键的是:你有没有检查浏览器开发者工具 Network 面板里,实际发出的请求头是不是真的就是 Content-Type: application/json
有时候中间件(比如 nginx、网关)会偷偷改头,或者你本地 devServer 有代理配置覆盖了请求头。

最稳妥的写法是:

await axios.post(
'/api/login',
{ username: 'test', password: '123' },
{
headers: {
'Content-Type': 'application/json'
},
transformRequest: [function (data, headers) {
// 确保 headers 被正确设置,且数据被显式转成 JSON
headers['Content-Type'] = 'application/json';
return JSON.stringify(data);
}]
}
);


不过其实更常见的坑是:你没传 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 升级后默认序列化逻辑有点微妙变化,你最好确认下请求体和头是不是对得上。
点赞 3
2026-02-26 14:03