🤔发生肾么事了
笔者在使用 Nginx 搭建站点test.henchat.net。架构如下:
- 前端:Nginx stream,使用
ssl_preread做 SNI 分流 - 后端:Nginx 监听内部端口 10443,处理 HTTPS
- 后端有目录补全逻辑(例如
/xxx→/xxx/)
然而搭建好后遇到了一个非常诡异的问题。当用户访问:
https://test.henchat.net/xxx
后端会返回:
301 → https://test.henchat.net:10443/xxx/
访问 https://test.henchat.net/xxx 时,后端返回的 301 跳转竟然变成了 https://test.henchat.net:10443/xxx/
看起来像是 Nginx“泄漏”了内部端口,但其实这是 Nginx 的默认行为导致的。本文将解释为什么会出现这种情况,以及如何用 port_in_redirect 设置完美解决。
😮根本原因
Nginx 在生成 301/302 跳转时,会自动使用以下变量:
$scheme(https)$host(test.henchat.net)$server_port(后端监听端口)
如果后端监听:
listen 10443 ssl;
那么 $server_port 就是 10443。
于是 Nginx 构造出的跳转 URL 就变成:
https://test.henchat.net:10443/xxx/
这就是内部端口“泄漏”的根本原因。
🛠️解决方法
只需在后端 10443 的 server 块中加入 port_in_redirect off; 即可解决:
server {
listen 10443 ssl;
server_name test.henchat.net;
port_in_redirect off; # <-加入
...
}
关于“port_in_redirect”的说明
port_in_redirect 控制 重定向 URL 是否包含端口号。默认值是:
port_in_redirect on;
表示:
重定向 URL 必须带上
$server_port。
当你关闭它时,Nginx 构造跳转 URL 时就会忽略端口号。而这才是我们想要的行为。
