proxy_redirect必须用于修正后端返回的location头,否则https请求会降级为http跳转且无法自动补全ssl协议或端口;其通过字符串前缀匹配重写location和refresh响应头,需严格对齐proxy_pass斜杠规则并配合x-forwarded-proto头实现兜底保障。

必须用 proxy_redirect 修正后端返回的 Location 头,否则 HTTPS 请求会降级成 HTTP 跳转,且无法自动补回 SSL 端口(如 443)或协议标识。
为什么后端重定向会丢掉 HTTPS 协议
后端服务(如 Spring Boot、Express)生成 301/302 跳转时,通常直接读取自身监听地址:http://127.0.0.1:8080/login。它看不到用户实际走的是 HTTPS,除非你显式传入上下文。
- 即使配置了
proxy_set_header X-Forwarded-Proto $scheme;,部分老框架或自定义 redirect 逻辑仍会忽略该 header,继续拼出http://开头的地址 - Nginx 默认不干预响应头,
Location原样透出,浏览器就真的去请求http://example.com/dashboard - 若 Nginx 监听在非标 HTTPS 端口(如
:777),后端更不可能知道该写https://example.com:777
proxy_redirect 怎么强制补上 https:// 和端口
核心是用 proxy_redirect 在响应发出前,把后端返回的错误协议前缀替换成正确公网地址。它只改 Location 和 Refresh 响应头,不影响正文。
- 最稳妥写法(推荐):
proxy_redirect http://127.0.0.1:8080/ https://$host:$server_port/;—— 显式带端口,适配非标 HTTPS 端口(如 777) - 如果确定永远走标准 443,可省略端口:
proxy_redirect http://127.0.0.1:8080/ https://$host/; - 要兼容 HTTP/HTTPS 入口(比如测试环境走 80,生产走 443):
proxy_redirect ~^http://[^/]+:8080(/.*)?$ $scheme://$host$server_port$1; - 注意:正则中
$server_port在 HTTPS 下是 443,但浏览器默认不显示;若需显式出现在 URL 中(如调试用),得写死或用 map 变量
常见踩坑点:proxy_pass 斜杠 + proxy_redirect 前缀必须严格对齐
proxy_redirect 的匹配是字符串前缀匹配,**协议、主机、端口、末尾斜杠缺一不可**。而它是否生效,又高度依赖 proxy_pass 末尾有没有 /。
- 若
proxy_pass http://backend:8080/api/;(带尾部/),后端返回Location: /login→ 此时proxy_redirect应配相对路径:proxy_redirect / /api/; - 若
proxy_pass http://backend:8080;(不带尾部/),后端返回Location: http://127.0.0.1:8080/login→proxy_redirect必须完整匹配:proxy_redirect http://127.0.0.1:8080/ https://$host/; - 用
curl -I验证:看响应头中Location:是否已变成https://开头;没变说明规则没命中,优先检查前后缀是否一字不差
为什么不能只靠 X-Forwarded-Proto 让后端自己修
传 header 是让后端“有机会”生成正确跳转,但 proxy_redirect 是 Nginx 层“兜底修正”。两者不是二选一,而是必须共存。
- 后端框架版本低、中间件拦截顺序错、或用了硬编码 redirect(如
response.sendRedirect("http://...")),X-Forwarded-Proto就完全失效 -
proxy_redirect不依赖后端配合,只要响应是 301/302,就无条件替换Location,稳定可靠 - 漏掉
proxy_set_header X-Forwarded-Proto $scheme;会导致后端静态资源链接、API 调用也生成 http 地址,这类问题proxy_redirect无法覆盖
真正容易被忽略的是:当 Nginx 监听多个端口(如同时开 80 和 443)时,$server_port 在不同请求里值不同,而 proxy_redirect 规则只写一次——这时候必须用正则 + $scheme 和 $server_port 变量动态构造,硬编码域名或端口必然在某条路径下失效。











