nginx反向代理层统一配置cors是最稳定解法,需将add_header置于proxy_pass所在location块内、显式处理options预检并return 204、用map实现多源动态白名单、加always参数确保错误响应也生效。

直接在 Nginx 反向代理层统一注入 CORS 响应头,是最稳定、无需改动前后端代码的解法。关键不是“加头”,而是把头加对位置、处理好预检、适配多源策略。
必须把 CORS 配置写在 proxy_pass 所在的 location 块内
很多人把 add_header 放在 server 或 root location 下,结果 API 有头、静态资源也有头,甚至健康检查接口也被污染。CORS 头只该作用于被代理的 API 路径。
- ✅ 正确:location /api/ { proxy_pass http://backend:8000/; add_header ...; if (OPTIONS) { ... } }
- ❌ 错误:location / { add_header ...; proxy_pass ...; } —— 这会让 /favicon.ico、/health 等也带上 CORS 头,可能干扰监控或缓存
- 注意 proxy_pass 末尾斜杠:proxy_pass http://backend:8000/(带斜杠)会剥离 /api;不带则原样转发,路径匹配逻辑完全不同
预检请求(OPTIONS)必须显式返回 204,不能只加头
浏览器发起跨域请求前,先发一个 OPTIONS 请求试探权限。如果 Nginx 没拦截并快速响应,就会把请求转发给后端——而多数后端根本不处理 OPTIONS,直接 404 或 502,导致跨域失败。
- if ($request_method = 'OPTIONS') { add_header ...; return 204; } 是必需步骤
- return 204 不带响应体,符合规范;用 return 200 + 空 body 容易因 Content-Length 不一致引发问题
- 所有 add_header 在 if 块里要重复写一遍——Nginx 的 add_header 不继承,if 内是独立作用域
多前端域名需动态白名单,禁用通配符 + credentials
开发时用 * 很方便,但一旦启用 withCredentials(如带 cookie 登录),Access-Control-Allow-Origin 就不能再用 *,否则浏览器直接拒绝。
- 用 map 指令构建 Origin 白名单:map $http_origin $cors_origin { default ""; "~^http://localhost(:\d+)?$" "$http_origin"; "~^https://app\.yourcompany\.com$" "$http_origin"; }
- 再在 location 中引用:add_header 'Access-Control-Allow-Origin' $cors_origin always;
- 配合 add_header 'Access-Control-Allow-Credentials' 'true',才能支持登录态透传
确保响应头真正生效,避开 Nginx 缓存与覆盖陷阱
add_header 默认不作用于 3xx/4xx/5xx 响应,且会被 upstream 响应头覆盖。几个关键点:
- 加上 always 参数:add_header ... always; 否则 401、500 等错误响应不会带 CORS 头
- proxy_hide_header 检查:确认没写 proxy_hide_header Access-Control-Allow-Origin —— 这会主动删掉你加的头
- 重载后用 curl -I http://your-nginx/api/test 验证响应头是否出现,比仅看浏览器控制台更可靠











