nginx跨域需避免响应头重复:后端与nginx不可同时输出cors头;应通过proxy_hide_header清除后端头,再用add_header ... always统一注入,并单独处理options预检请求。

当 Nginx 作为反向代理或负载均衡器时,若后端服务(如 Java、Node.js、Go 应用)已自行输出 Access-Control-Allow-Origin 等 CORS 响应头,而 Nginx 又未做干预,就容易出现多个同名响应头并存的情况。浏览器会拒绝这种非法响应,报错类似:
“The 'Access-Control-Allow-Origin' header contains multiple values”
根本原因不是 Nginx 发送了重复头,而是它把后端返回的 CORS 头原样透传,又在自身配置中用 add_header 再加一遍——最终导致响应中出现两个甚至多个 Access-Control-Allow-Origin。解决的关键,是让 Nginx 主动“拦截”后端发来的 CORS 头,再由自己统一、干净地注入。
明确谁该负责 CORS 控制权
不要让 Nginx 和后端同时写 CORS 头。二选一:
- 推荐方案:Nginx 统一管理,后端完全关闭所有 CORS 相关响应头(如 Spring 的
@CrossOrigin、Express 的cors()中间件、手动res.setHeader) - 备选方案:后端全量控制,Nginx 不设任何
add_header Access-Control-*,仅做纯透传
若选择前者(更常见、更可控),就必须清除后端可能混入的旧头,否则它们会和 Nginx 新加的头冲突。
用 proxy\_hide\_header 清除后端透传的 CORS 头
在 location 块或 upstream 后的 proxy_pass 上下文中,添加以下指令:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
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;proxy_hide_header Access-Control-Max-Age;
注意:proxy_hide_header 只影响从后端收到的响应头,对 Nginx 自己用 add_header 添加的头无影响。它必须放在 proxy_pass 所在的 location 块内,且优先级高于后端响应。
配合 add\_header always 安全注入新头
清除旧头后,用 add_header ... always 显式添加你认可的 CORS 头。always 参数至关重要——它确保即使响应状态码是 204(如 OPTIONS 预检)或 302,头也不会被丢弃:
-
add_header 'Access-Control-Allow-Origin' 'https://your-fe.com' always;(勿用*配true) 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;
如果需要支持 Origin 白名单(而非固定域名),可配合 map 指令动态赋值 $cors_origin,再用于 add_header。
别忘了处理 OPTIONS 预检请求
很多跨域失败实际卡在预检阶段。Nginx 应直接响应 OPTIONS 请求,不转发给后端:
- 在 location 块内加:
if ($request_method = 'OPTIONS') { add_header 'Access-Control-Max-Age' 1728000 always; return 204; } - 确保该
if块中所有add_header都带always,否则 204 响应里不会包含 CORS 头 - 避免在
if外重复设置相同头,防止叠加
这样既减轻后端压力,又能保证预检响应干净、合规、单值。










