根本原因是浏览器对重定向链每步独立校验cors,新请求不带origin且不继承响应头;需nginx拦截302、重写location并统一注入跨域头,同时后端应基于x-forwarded头生成正确跳转地址。

302 重定向时跨域头丢失,根本原因不是 Nginx “漏发”,而是浏览器对重定向链中每一步都独立校验 CORS:后端返回 302 后,浏览器会发起一个全新请求访问 Location 地址,这个新请求不带 Origin,也不继承原响应头。如果跳转目标没配好跨域策略,就会被拦截。
用 Nginx 拦截并重写 302 响应
不让 302 透传给浏览器,由 Nginx 主动接管跳转,并统一注入跨域头:
- 启用错误拦截:
proxy_intercept_errors on; - 捕获重定向状态码:
error_page 301 302 = @handle_redirect; - 在命名 location 中完成跳转并加头:
```nginx
@handle_redirect {
add_header 'Access-Control-Allow-Origin' '$http_origin' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
return 302 $sent_http_location;
}
```
注意:@handle_redirect必须是internal,且所有头都必须带always
修正 Location 头中的跳转地址
后端生成的 Location 常含内网 IP、错误协议或缺失路径前缀,需用 proxy_redirect 重写:
- 替换内网地址为当前域名:
proxy_redirect http://192.168.1.100:8080/ https://$host/api/; - 正则匹配多种内网 host:
proxy_redirect ~^http://[^/]+(?::\d+)?/(.*)$ https://$host/api/$1; - 补全路径前缀(如代理路径是
/api/,但后端返回/login):proxy_redirect / /api/;
让后端生成正确的跳转地址
Nginx 只能兜底改头,治本要后端知道自己被代理:
- 透传协议:
proxy_set_header X-Forwarded-Proto $scheme; - 透传原始 Host:
proxy_set_header Host $http_host; - (可选)声明路径前缀:
proxy_set_header X-Forwarded-Prefix /api/; - 后端需读取这些头拼接跳转 URL,避免硬编码内网地址
防止 OPTIONS 预检被重定向干扰
若后端有 HTTP → HTTPS 全局跳转,可能把 OPTIONS 请求也 301 了,导致预检失败:
- 确保后端中间件中 CORS 配置早于 HTTPS 重定向逻辑
- 或在 Nginx 层单独处理:
if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin "$http_origin" always; add_header Access-Control-Allow-Credentials "true" always; add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always; add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always; add_header Access-Control-Max-Age 1728000; return 204; }











