add_header 不适合处理 CORS 验证,因其无法区分预检请求、不支持源白名单判断、在嵌套 location 中易被覆盖;应改用 more_set_headers + if 动态设置头,并显式拦截 OPTIONS 请求返回 204。

直接用 add_header 在 Nginx 反向代理中解决 CORS 问题,看似简单,实则容易踩坑——它不能覆盖预检请求(OPTIONS)的响应头,也不支持条件判断,更会在多级 location 中被覆盖。真正可靠的做法是避开 add_header 的局限,改用更可控的配置方式。
为什么 add_header 不适合处理 CORS 验证
add_header 是静态指令,每次响应都会原样添加,但 CORS 验证有三个关键动态性它无法满足:
- 浏览器对非简单请求会先发 OPTIONS 预检,而
add_header无法区分 GET/POST 和 OPTIONS,导致预检响应缺失必要头(如Access-Control-Allow-Methods) - 生产环境通常只允许特定域名,而
add_header 'Access-Control-Allow-Origin: *'违反安全规范,且不支持正则匹配或白名单判断 - 在嵌套的
location块中,add_header会继承并叠加,造成重复或冲突(例如两个add_header Access-Control-Allow-Credentials true)
用 more_set_headers + if 实现精准源验证
Nginx 的 more_set_headers 指令(需启用 headers-more-nginx-module)配合 if 条件,可动态设置响应头,适配真实业务场景:
- 先用
if匹配合法来源,把域名存入变量:set $cors ""; if ($http_origin ~* "^https?://(app\.yourcompany\.com|dashboard\.yourcompany\.com)$") { set $cors $http_origin; } - 再用
more_set_headers安全注入头:more_set_headers 'Access-Control-Allow-Origin: $cors';<br>more_set_headers 'Access-Control-Allow-Credentials: true';<br>more_set_headers 'Access-Control-Allow-Methods: GET, POST, OPTIONS';<br>more_set_headers 'Access-Control-Allow-Headers: Authorization, Content-Type, X-Requested-With';
- 确保该配置放在
server块顶层(location外),避免被子块覆盖
必须拦截并响应 OPTIONS 预检请求
仅设置响应头还不够,浏览器预检失败时根本不会发真实请求。必须显式处理 OPTIONS 方法:
- 在对应 API 的
location中添加:if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin $cors; add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; add_header Access-Control-Allow-Credentials 'true'; add_header Access-Control-Allow-Headers 'Authorization, Content-Type'; add_header Access-Control-Max-Age 86400; add_header Content-Length 0; add_header Content-Type 'text/plain; charset=utf-8'; return 204; } - 注意:此处
add_header仅用于 OPTIONS 响应,与主逻辑隔离,不会污染其他方法 - 返回
204 No Content符合规范,比200更轻量
上线前务必验证的三件事
配置生效 ≠ CORS 通过,需逐项确认:
- 用
curl -I -H "Origin: https://app.yourcompany.com" https://your-api.com/v1/user检查响应头是否含Access-Control-Allow-Origin: https://app.yourcompany.com - 用
curl -X OPTIONS -I -H "Origin: https://app.yourcompany.com" -H "Access-Control-Request-Method: POST" https://your-api.com/v1/user验证预检响应是否完整 - 打开浏览器 DevTools → Network → 查看请求的
Response Headers,确认没有重复头或Access-Control-Allow-Origin: *等不合规值











