核心是“先清后立”:用proxy_hide_header拦截后端cors头,再由nginx统一注入合规头,避免浏览器因重复头或credentials-origin冲突而拒绝响应。

核心是“先清后立”:用 proxy_hide_header 把后端返回的 CORS 头全部拦下,再由 Nginx 统一、干净地注入,避免浏览器收到重复头而直接拒绝响应。
为什么必须隐藏后端 CORS 头
当 Java、Go 或 Node.js 后端已自行设置了 Access-Control-Allow-Origin 等头,而 Nginx 又在 location 里用 add_header 再加一遍,就会导致响应中出现两个同名头。浏览器(尤其是 Chrome)对这类重复头处理严格:
- 预检请求(OPTIONS)返回非 200(如被静默截断),报错 “Response to preflight request doesn’t pass access control check”
- 实际请求即使状态码是 200,也会被拦截,控制台提示 “has been blocked by CORS policy”
- 若
Access-Control-Allow-Origin是通配符*,但同时设了Access-Control-Allow-Credentials: true,浏览器会直接拒收——这不是配置错误,而是规范强制要求
关键配置步骤(location 块内顺序不能错)
所有操作必须写在 proxy_pass 所在的 location 块中,且按以下顺序执行:
安全更新和维护 CLI Proxy API(CPA)部署与配置。用于 CPA 镜像升级、配置变更、认证目录兼容修复、上线验证与回滚。适用于用户提到“CPA 更新/升级/配置改了/容器重建/回滚”等场景。
- 先屏蔽后端返回的冲突头(每行一条,不可合并):
proxy_hide_header Access-Control-Allow-Origin;
proxy_hide_header Access-Control-Allow-Methods;
proxy_hide_header Access-Control-Allow-Headers;
proxy_hide_header Access-Control-Allow-Credentials;
proxy_hide_header Access-Control-Expose-Headers; - 再统一注入合规头(务必加
always,否则对 3xx/4xx 响应不生效):
add_header 'Access-Control-Allow-Origin' 'https://your-frontend.com' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Expose-Headers' 'X-Request-ID, Content-Length' always; - 单独处理 OPTIONS 预检请求(不转发给后端,直接响应):
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
容易忽略的两个安全细节
这两点不满足,整个 CORS 配置形同虚设:
-
Credentials 和 Origin 必须匹配:如果需要携带 Cookie(即
Access-Control-Allow-Credentials: true),则Access-Control-Allow-Origin不能是*,必须写具体协议+域名,例如https://app.example.com -
确保没有其他 location 或 server 块重复注入相同头:检查全局配置,避免多个
add_header叠加;安全头如Strict-Transport-Security、X-Frame-Options也建议用proxy_hide_header屏蔽后端输出,统一由 Nginx 控制
验证是否生效
用 curl 检查真实响应头,确认无残留、无重复:
curl -I https://your-domain/api/test
正确结果应满足:
- 只出现一次
Access-Control-Allow-Origin,值为你在 Nginx 中指定的那个 - 没有
Access-Control-Allow-Origin、Access-Control-Allow-Credentials等头来自后端(可通过对比关掉 Nginx 代理直连后端来比对) - OPTIONS 请求返回 204,且含
Access-Control-Max-Age和Content-Length: 0










