需隐藏后端cors头,避免与nginx注入的重复导致预检失败或请求被拦截;应先用proxy_hide_header屏蔽,再用add_header ... always统一注入合规头,并单独处理options请求。

直接在 Nginx 的 location 块中用 proxy_hide_header 屏蔽后端返回的 CORS 头,再由 Nginx 统一注入合规的跨域响应头,就能避免重复或冲突。
为什么需要隐藏后端 CORS 头
当后端服务(如 Java、Go 或 Node.js 应用)已自行设置了 Access-Control-Allow-Origin 等头,而 Nginx 又在同一 location 中用 add_header 再加一遍,浏览器就会收到重复响应头。这会导致:
- CORS 预检(OPTIONS)失败,报错 “has been blocked by CORS policy: Response to preflight request doesn’t pass access control check”
- 实际请求被拦截,即使状态码是 200
- 部分浏览器(如 Chrome)会直接拒绝含重复
Access-Control-Allow-Origin的响应
关键配置:先隐藏、再统一注入
在 proxy_pass 所在的 location 块中,按顺序执行以下操作:
- 用
proxy_hide_header明确屏蔽后端返回的冲突头:proxy_hide_header Access-Control-Allow-Origin;<br> proxy_hide_header Access-Control-Allow-Methods;<br> proxy_hide_header Access-Control-Allow-Headers;<br> proxy_hide_header Access-Control-Allow-Credentials;
- 用
add_header ... always重新注入干净、可控的 CORS 头:add_header 'Access-Control-Allow-Origin' 'https://your-frontend.com' always;<br> add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;<br> add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always;<br> add_header 'Access-Control-Allow-Credentials' 'true' always;
- 必须为预检请求单独处理:
if ($request_method = 'OPTIONS') {<br> add_header 'Access-Control-Max-Age' 1728000;<br> add_header 'Content-Type' 'text/plain; charset=utf-8';<br> add_header 'Content-Length' 0;<br> return 204;<br> }
特别注意两个安全细节
这两点不满足,即使配置正确也会被浏览器拒绝:
-
Origin 和 Credentials 不能共存于通配符:若
Access-Control-Allow-Origin设为*,则Access-Control-Allow-Credentials必须为false;如需传 Cookie,Origin 必须写具体域名(如https://fe.example.com),不可用通配符 - add_header 必须带 always 参数:否则 Nginx 在 204、302 等非 2xx 主体响应中默认不发送自定义头,导致 OPTIONS 预检失败
验证是否生效
用 curl 检查响应头是否干净:
- 发起 OPTIONS 请求:
curl -I -X OPTIONS -H "Origin: https://your-frontend.com" http://your-nginx-domain/api/test - 确认响应中只有 Nginx 注入的一组 CORS 头,没有重复项,且包含
Access-Control-Allow-Origin和204 No Content - 再发真实请求(如 POST),检查响应头是否仍保持一致,无后端残留头










