Nginx 应作为唯一跨域策略出口,关闭后端 CORS 中间件,通过 proxy_hide_header 屏蔽后端响应头,并用 add_header 统一注入合规跨域头;对 OPTIONS 请求显式拦截返回 204,确保跨域控制权集中、无冲突。

当后端微服务框架(如 Spring Boot、Express、FastAPI)已内置 CORS 中间件,又在 Nginx 层叠加跨域响应头时,极易出现响应头重复、冲突甚至被浏览器拒绝的情况——典型表现是 OPTIONS 预检失败、Access-Control-Allow-Origin 多次设置报错,或 withCredentials=true 时因 Origin: * 被拦截。关键不是“加更多头”,而是明确责任边界、避免双写。
明确跨域控制权归属
微服务架构中,Nginx 应作为唯一跨域策略出口,后端框架的 CORS 中间件必须关闭或降级为“仅内部调用生效”。否则:
- Spring Boot 的
@CrossOrigin或全局CorsConfiguration会输出自己的Access-Control-Allow-Origin,与 Nginx 的add_header冲突; - Node.js 的
cors()中间件默认返回Access-Control-Allow-Origin: *,若 Nginx 同时设为具体域名,浏览器将拒绝响应; - 预检请求(OPTIONS)可能被后端直接响应(返回 200),绕过 Nginx 的统一处理逻辑,导致后续实际请求因 header 不匹配而失败。
Nginx 层配置需主动屏蔽后端跨域头
Nginx 无法删除后端已写入的响应头,但可通过 proxy_hide_header 主动隐藏它们,再由自己重新注入统一、合规的跨域头:
- 在
location块中添加:proxy_hide_header Access-Control-Allow-Origin;proxy_hide_header Access-Control-Allow-Credentials;proxy_hide_header Access-Control-Allow-Methods;proxy_hide_header Access-Control-Allow-Headers; - 紧接着用
add_header重写全部跨域头,确保值一致且符合业务要求(例如:动态回传$http_origin,而非硬编码*); - 特别注意
Access-Control-Allow-Credentials: true必须配套Access-Control-Allow-Origin为具体域名,不能为*—— Nginx 配置中这两者必须成对出现且逻辑自洽。
对 OPTIONS 预检请求做显式拦截与响应
避免后端框架处理 OPTIONS 请求,全部交由 Nginx 短路响应:
- 在对应
location块内添加:if ($request_method = 'OPTIONS') {add_header Access-Control-Allow-Origin "$http_origin";add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";add_header Access-Control-Allow-Credentials "true";add_header Access-Control-Max-Age 3600;add_header Access-Control-Expose-Headers "Content-Length,Content-Range";return 204;} - 该写法确保所有 OPTIONS 请求不发往后端,Nginx 直接返回 204 空响应 + 正确跨域头,既提升性能,也彻底规避后端中间件干扰;
- 注意:
if在 location 内使用是安全的,但不可用于 server 级别或嵌套复杂逻辑。
验证与调试要点
上线前务必通过真实请求验证 header 行为:
- 用 curl 模拟预检:
curl -X OPTIONS -H "Origin: https://web.example.com" -H "Access-Control-Request-Method: POST" -I http://api.example.com/api/user,检查返回头是否只有 Nginx 输出、无后端残留; - 浏览器开发者工具 → Network → 查看响应头,确认
Access-Control-Allow-Origin值与前端 origin 完全一致(非*),且Vary: Origin存在(Nginx 自动添加,表明支持多源); - 若仍报错,检查 Nginx error log 中是否有
duplicate header提示,并确认后端日志里 OPTIONS 请求是否已被完全拦截。


















