为什么CORS预检请求返回403时,我的自定义头被服务器拒绝了?

诸葛利伟 阅读 751

最近在做跨域文件上传时遇到个问题:前端用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头配置上。

我来解答 赞 9 收藏
二维码
手机扫码查看
2 条解答
♫诗诗
♫诗诗 Lv1
试试看把 Content-Type 也加到 Access-Control-Allow-Headers 里——你虽然写了,但可能没生效,因为 multipart/form-dataContent-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", "*") 临时测试下,如果通了,再精确配置。
点赞 1
2026-02-24 13:10
南宫秋梓
你这个配置看起来只差一步了。问题出在服务器允许的 headers 没有正确覆盖所有自定义头字段。你已经在 Access-Control-Allow-Headers 里加了 X-File-Hash,但如果你用了认证或者 cookies,还要显式加上 Authorization 或者 X-Requested-With 这类默认安全头,否则浏览器也会拒绝。

另外,你的中间件写法有个坑: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");

这些都加上以后再试试,应该能解决头被拒绝的问题。
点赞 9
2026-02-05 20:11