为什么CORS预检请求返回403时,我的自定义头被服务器拒绝了?
最近在做跨域文件上传时遇到个问题:前端用fetch发送POST请求带了multipart/form-data格式和自定义头X-File-Hash,但预检OPTIONS请求一直返回403。服务器日志显示:”Request header field X-File-Hash is not allowed by CORS policy”。
我检查过服务器配置,确实设置了
// Node.js Express配置示例
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "https://myfrontend.com");
res.header("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
res.header("Access-Control-Allow-Headers", "X-File-Hash, Content-Type");
next();
});
但奇怪的是,当我把X-File-Hash头从请求中移除后,请求就能成功。难道服务器配置需要显式允许所有安全敏感头?或者预检请求需要额外的验证步骤?
另外,我在前端CSS里尝试过设置
.upload-form {
/* 这个样式和问题无关,但想确认是否影响请求头 */
content: attr(data-x-file-hash);
}
结果发现样式不影响问题,核心问题还是在CORS头配置上。
Content-Type也加到Access-Control-Allow-Headers里——你虽然写了,但可能没生效,因为multipart/form-data的Content-Type带 boundary 参数时,浏览器会把它当成“非简单请求头”,服务器必须显式允许它,哪怕你写的是Content-Type而不是Content-Type: multipart/form-data; boundary=...。正确配置应该是:
res.header("Access-Control-Allow-Headers", "X-File-Hash, Content-Type");但要注意:如果你在前端请求里没手动设置
Content-Type(让 fetch 自动加 boundary),那服务端的Access-Control-Allow-Headers必须包含Content-Type,而且不能只写死值,要允许这个字段存在——你写的配置本身没问题,但可能被中间件(比如 cors 库或 nginx)覆盖了。建议先用
res.header("Access-Control-Allow-Headers", "*")临时测试下,如果通了,再精确配置。另外,你的中间件写法有个坑:res.header 在 Express 里推荐用 response.header(key, value) 多次调用,而不是链式写法,否则可能某些 header 没传进去。建议改成这样:
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "https://myfrontend.com");
res.header("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
res.header("Access-Control-Allow-Headers", "X-File-Hash, Content-Type, Authorization");
next();
});
还有一个点是,有些服务器框架(比如 Express 的某些 CORS 插件)在处理 OPTIONS 请求时需要特别处理,建议加个专门的 OPTIONS 路由兜底:
app.options('/your-upload-path', (req, res) => {
res.sendStatus(200);
});
最后,如果你前端设置了 credentials: 'include',那服务器还必须设置 Access-Control-Allow-Credentials,否则也可能触发 403。这个配置也要加进去:
res.header("Access-Control-Allow-Credentials", "true");
这些都加上以后再试试,应该能解决头被拒绝的问题。