唯一可靠做法是用set $real_scheme $http_x_forwarded_proto;读取上游x-forwarded-proto,缺失时兜底$scheme,再以$real_scheme生成302跳转url,并向下透传proxy_set_header x-forwarded-proto $real_scheme;。

在多级反向代理(比如 CDN → Nginx A → Nginx B → 后端)环境下,Nginx 发起 302 跳转时,若直接用 $scheme 或硬写 http:///https://,极易生成错误的跳转地址——例如跳到 http://example.com(明明用户访问的是 HTTPS),或跳到内网地址、带端口的地址。根本原因在于:Nginx 默认不信任上游传来的协议信息,$scheme 只反映当前这层 Nginx 接收请求时的协议(可能是 HTTP,即使用户走的是 HTTPS),而非原始客户端的真实协议。
必须传递并信任 X-Forwarded-Proto
上游代理(CDN 或前一级 Nginx)需在转发请求时,显式设置 X-Forwarded-Proto 头,值为 http 或 https。你的这层 Nginx 必须主动读取它,并用作跳转依据:
- 在 server 或 location 块中添加:
set $real_scheme $http_x_forwarded_proto; - 若上游未传该头(如直连或配置遗漏),可设兜底:
set $real_scheme $scheme; - 跳转时用
$real_scheme拼目标 URL,例如:return 302 $real_scheme://new.example.com$request_uri;
确保 proxy_set_header 正确透传
如果你这层 Nginx 同时也做反向代理(比如把请求再发给后端),那它本身也要把真实协议头继续往下传,否则下一层也无法正确判断:
proxy_set_header X-Forwarded-Proto $real_scheme;- 同时建议补全:
proxy_set_header X-Real-IP $remote_addr;和proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - 避免在 proxy_pass 前使用 if 或 rewrite 干扰 header 设置顺序
验证 Location 头是否合规
302 响应中的 Location 头必须是完整、可访问的 URL。常见错误包括:
- 协议写死为
http,导致 HTTPS 用户跳转后降级(混合内容或被浏览器拦截) - 域名拼错,如漏掉
www或用了测试域名 - 路径用
$uri而非$request_uri,导致查询参数(?a=1&b=2)丢失
用 curl -I http://your-domain/path 查看响应头,确认 Location: 的值与用户实际访问协议一致,且包含完整路径和参数。
避免多级代理下的循环跳转
当多层 Nginx 都配置了类似逻辑,容易因 header 重复或条件误判引发无限跳转:
- 检查每层是否都设置了
X-Forwarded-Proto,且值未被覆盖或篡改 - 不要在多个 location 或 if 块中重复写 return 302,优先收敛到一个明确的匹配块
- 可在跳转前加简单判断,例如:
if ($real_scheme = "") { return 500; },快速暴露 header 缺失问题











