核心是让Nginx主动拦截修正后端生成的错误重定向URL,而非依赖后端正确生成;需检查access.log中301/302响应的Location头是否含内网地址或错协议,透传X-Forwarded-Proto并配置proxy_redirect正则匹配替换。
核心是确认后端生成的重定向 URL 是否含错误协议、错误域名或错误路径,并让 Nginx 主动拦截修正,而不是依赖后端自己写对。
看 access.log 里的 Location 响应头
打开 /var/log/nginx/access.log,重点查带 301/302 的请求行,用这行命令快速提取:
- awk '$9 ~ /^(301|302)$/ {print $1, $7, $9, $13}' /var/log/nginx/access.log | tail -10
-
$13 就是 $upstream_http_location,即后端返回的原始跳转地址
- 如果看到类似 http://localhost:8080/login、https://127.0.0.1:8443/ 或 http://mydomain.com:443/ 这类地址,说明后端把内部地址或错端口当成了对外地址
检查后端是否识别 HTTPS 协议
后端若只读 request.scheme 或 $_SERVER['HTTPS'],而没解析 X-Forwarded-Proto,就会误判为 HTTP:
- 确保 Nginx 配置中包含:proxy_set_header X-Forwarded-Proto $scheme;
- Spring Boot 要配:server.forward-headers-strategy=framework
- Django 需设:SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
- WordPress 在 wp-config.php 开头加:if ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') $_SERVER['HTTPS'] = 'on';
验证根路径(root path)是否与前端路由一致
比如你部署在 https://example.com/myapp,但后端硬编码了 / 作为应用根路径,它生成的跳转就可能是 /login → Nginx 没做路径剥离,直接转发给后端,后端又跳回 /login,形成循环:
- 后端需配置实际上下文路径,如 Spring Boot 的 server.servlet.context-path=/myapp
- Nginx location 中要匹配该前缀,例如:location /myapp/ { proxy_pass http://backend/; }(注意结尾斜杠,实现路径重写)
- 避免 proxy_pass http://backend/myapp; 这种写法,容易导致双重拼接
用 proxy_redirect 主动修正错误跳转
即使后端协议和路径都错了,Nginx 也能兜底改写:
- 加这一行(放在 proxy_pass 后面):proxy_redirect ~^https?://[^/]+(/.*)$ $scheme://$host/myapp$1;
- 如果后端返回的是相对路径(如 Location: /login),则需配合 proxy_redirect / /myapp/; 把根路径映射过去
- 测试是否生效:用 curl -I https://example.com/myapp/login 看响应头中的 Location 是否已变成 https://example.com/myapp/login