答案是通过$upstream_http_location、$status和$upstream_status三字段交叉比对,可精准区分nginx自身生成还是后端返回的301重定向,并定位location头构造错误;配合absolute_redirect off、port_in_redirect off等配置可解决容器化环境端口泄露问题。

直接看 Nginx access.log 中的 $upstream_http_location 字段,再结合 $status 和 $upstream_status 三字段交叉比对,就能快速定位是 Nginx 自身生成的 301 还是后端返回的 301,以及 Location 头是否被错误构造——这是最高效、最贴近真实链路的排查方式。
盯住三个关键日志字段
打开 /var/log/nginx/access.log,每条记录包含一次完整请求生命周期。重点提取以下三项:
-
$status:Nginx 最终返回给客户端的状态码。若为301,说明发生了重定向;若为404或502,需区分是 Nginx 未匹配 location,还是后端异常导致转发失败。 -
$upstream_status:后端服务实际返回的状态码。例如看到301 301,代表后端确实发出了重定向;若为301 502,说明 Nginx 收到重定向响应前已与后端断连。 -
$upstream_http_location:后端原始响应头中Location的值。这是核心线索——如果它含http://localhost:8080/、https://backend:8443/或不带端口的https://example.com/(而你对外暴露的是:9279),就确认问题出在 Location 构造环节。
快速筛出异常重定向请求
不用翻日志,用一条命令即可聚焦问题:
- 查内网地址或非标端口泄露:
awk '$9==301 {print $13}' /var/log/nginx/access.log | grep -E "(192\.|10\.|172\.)|:[0-9]{4}" | tail -10 - 对比正常与异常路径跳转:
grep "/login" /var/log/nginx/access.log | tail -5和grep "/dashboard" /var/log/nginx/access.log | tail -5,观察$upstream_http_location是否一致、是否缺失外部端口。
检查 Nginx 配置中三类关键指令
容器化环境中端口丢失,往往不是后端问题,而是 Nginx 默认行为与 Docker 端口映射不兼容所致:
-
absolute_redirect off;:禁用绝对路径重定向,强制生成相对路径(如/login/),避免拼接 Host 和端口。适用于目录自动补斜杠等 Nginx 自触发 301 场景。 -
port_in_redirect off;:关闭重定向时自动追加监听端口的行为。特别适合宿主机映射非标端口(如-p 9279:80)时,防止 Nginx 把:9279当作内部端口写进 Location。 -
server_name_in_redirect off;:禁用用server_name替换 Host 的逻辑,让 Nginx 信任请求头中的原始 Host(含端口),避免覆盖掉客户端真实访问端口。
验证代理链路是否透传关键头信息
若 301 来自后端(如 Spring Boot 或 Node.js),则问题根源常在协议和端口感知缺失:
- 确认 Nginx 已设置:
proxy_set_header X-Forwarded-Proto $scheme;和proxy_set_header Host $host:$server_port;(或$host+ 显式端口变量)。 - 检查后端是否依据
X-Forwarded-Proto构建跳转地址。例如 Spring Boot 需配置server.forward-headers-strategy=framework,Node.js Express 应启用app.set('trust proxy', true)。 - 若后端硬编码了
http://或内部端口,仅靠 Nginx 无法根治,必须配合proxy_redirect修正,例如:proxy_redirect http://127.0.0.1:3000/ https://$host:9279/;。











