为什么Vue请求带自定义头防CSRF时头信息被浏览器自动过滤了?
我在Vue项目里用axios发送POST请求时,按教程设置了X-Requested-With和自定义头,但后端收到的请求头里这两个字段完全消失了,这是什么情况?
代码是这样的:
methods: {
submitForm() {
axios.post('/api/data', this.formData, {
headers: {
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-Token': 'abc123'
}
})
}
}
我检查了CORS配置,后端确实返回了Access-Control-Allow-Headers: X-Requested-With,X-CSRF-Token,但开发者工具网络面板显示这两个头根本没有被发送。难道是Vue的axios配置有问题?或者浏览器有其他限制?
问题就出在这里:X-Requested-With和X-CSRF-Token这两个头,虽然看起来常见,但一旦加上去,浏览器就会认为这是非简单请求,必须后端明确允许才能继续。即使你前端写了headers,浏览器在预检失败的情况下根本不会把实际请求发出去,所以你在网络面板里看到的请求压根就没带这些头。
解决的关键有三点:
第一,确认后端已经正确响应OPTIONS请求,返回了Access-Control-Allow-Origin、Access-Control-Allow-Methods,还有最重要的Access-Control-Allow-Headers,并且里面确实包含了X-Requested-With和X-CSRF-Token这两个字段。
第二,确保后端对OPTIONS请求返回200而不是405,很多人忽略了给OPTIONS方法加路由处理,导致预检失败。
第三,你可以暂时把X-Requested-With换成XMLHttpRequest以外的值试试,其实很多框架用这个头只是为了识别AJAX请求,但现在都走CORS了,其实可以不用硬加。如果你只是想防CSRF,专注处理好X-CSRF-Token就行。
我建议你打开浏览器开发者工具,点开那个失败的请求,看下是不是有OPTIONS请求出现,状态是不是200。如果是403或405,那就是后端没处理好预检请求。
代码上你的写法没问题,问题大概率是后端没正确响应预检。比如Node.js Express的话得加个中间件:
改完之后再试,应该就能看到头信息正常发送了。
具体来说,你用的X-Requested-With和X-CSRF-Token属于“非简单请求头”,浏览器在发送前会先发一个OPTIONS预检请求(preflight),询问服务器是否允许这些自定义头。只有服务器明确同意,浏览器才会继续发真正的POST请求。
你现在的情况应该是:虽然后端加了Access-Control-Allow-Headers,但OPTIONS请求返回的状态码不对,或者响应头没正确返回,导致预检失败,所以你的POST根本没发出去——你在开发者工具里看到的请求可能就是那个OPTIONS请求,而它之后没有跟着POST,说明被拦截了。
第一步,打开浏览器开发者工具的网络面板,找那个OPTIONS请求,看它的状态是不是200。如果不是,说明预检都没通过。然后看响应头有没有包含:
Access-Control-Allow-Origin: 对应你的前端域名
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: X-Requested-With, X-CSRF-Token
这三个必须都返回,缺一不可。
第二步,确保后端对OPTIONS请求返回200,不能抛异常或重定向。很多框架默认不处理OPTIONS,得手动加路由或中间件。
比如在Express里要这样写:
第三步,前端axios可以加个默认配置,避免每次都写:
但更关键的是,别依赖这个头来做CSRF防护。因为:
1. 浏览器会过滤掉(就像你现在遇到的)
2. 攻击者可以用同源页面发起请求,照样带上这些头
真正防CSRF应该用SameSite Cookie + CSRF Token双重验证。Token要从服务端生成,前端通过meta标签或接口获取,然后放在请求体或头里,后端比对。
比如后端渲染时注入:
<meta name="csrf-token" content="abc123">前端读取:
总结一下:你现在的问题不是代码写错了,而是CORS预检没过。先查OPTIONS请求的响应,确保头全、状态200。再考虑换更可靠的CSRF方案,别死磕这几个容易被拦的头。