外网访问打不开?3种场景根治端口转发丢端口
- 工作小总结&小工具类
- 时间:2026-08-21 12:54
- 24人已阅读
🔔🔔好消息!好消息!🔔🔔
有需要的朋友👉:微信号
外网访问打不开?3种场景根治端口转发丢端口
原创:凯哥Java
本文标签:路由器端口转发丢端口、SpringBoot重定向端口、Tomcat proxyPort配置
前两天一兄弟在群里喊:凯哥,我这在路由器上做了端口转发,外网访问 http://公网IP:17080/项目名 死活打不开,浏览器直接报无法连接。他第一反应就是路由器坏了、转发没配好。
我让他先别动路由器。这种「一访问就跳转到没端口的地址、然后打不开」的现象,我见得太多了——锅大概率不在路由器,在你后端那个 Web 应用身上。
摘要内容:外网访问端口转发地址打不开,常见原因是后端 Tomcat/SpringBoot 返回了不带公网端口的 301/302 重定向;路由器四层 NAT 不会改写 Location 头。本文给出 3 种场景的永久修复方案,含 SpringBoot、原生 Tomcat 与代码层写法。

一、先说结论:锅不在路由器,在你后端应用
先把现象还原一遍,你就明白了。
你在外网访问:
http://1.2.3.4:17080/your-app (末尾没加斜杠)
应用自己「啪」一下给你 301 跳转到:
http://1.2.3.4/your-app/ (:17080 没了)
浏览器拿到这个没有端口的地址,HTTP 默认走 80 端口,结果就是去敲 80——你内网服务又没监听 80,自然打不开。
🔥 重点来了:没有 Nginx、纯路由器端口转发的情况下,路由器本身不会主动去改 HTTP 的 Location 重定向头。端口之所以丢,100% 是你后端 Web 应用(Tomcat 或 SpringBoot 内置 Tomcat)自己吐了一个不带端口的 301/302。
想确认?在外网机器上敲一条命令看返回的 Location:
curl -I http://1.2.3.4:17080/your-app
你大概率会看到:
HTTP/1.1 301 Moved Permanently
Location: http://1.2.3.4/your-app/
下面这张是凯哥在外网机器上实际跑出来的响应头——Location 后面只跟了 IP,根本没带 17080,再点下去就会去打默认 80 端口:

✅ 实锤:跳转 URL 里压根没有 17080。根因不在网络,在应用。
二、根子在哪:四层 NAT 不会改 Location 头
一句话讲透:路由器做的端口转发,本质是四层(TCP)NAT,它只管把「外网某个端口的包」转给「内网某台机器的某个端口」,根本不解析、也不改写上层的 HTTP 报文。
你的链路自外而内只有三跳:
外网客户端 → 路由器 17080(公网入口)
│
▼ 端口转发
内网服务器 8080(真实监听端口)
路由器只做包级别的转发:把「公网 17080 收到的包」原样丢给「内网服务器 8080」。它不解析 HTTP,也不重写 Host/Location。所以到了内网服务器这一步,它只知道自己当时监听的是 8080,完全不晓得外面进来的用户敲的是 17080。

结果就是:Tomcat/SpringBoot 在生成「目录补斜杠」这类绝对跳转地址时,只拿自己监听的 8080 拼,完全不带上公网的 17080——拼出来的 Location 自然把公网端口丢了。
⚠️ 这点一定要分清:路由器端口映射 ≠ 反向代理。四层 NAT 没法把「外部访问端口」告诉后端程序;只有七层代理(Nginx/Apache)才能附加 X-Forwarded-Port、改写 Host 头,让后端知道「用户是从哪个公网端口进来的」。所以别再对着路由器一顿瞎调了。

三、3 种场景永久修复(含临时规避)
💡 先给一个立刻能用、不用改代码的临时方案:访问时地址末尾强制加上斜杠:
http://1.2.3.4:17080/your-app/
带上 / 之后,很多 Web 容器不会触发「目录补斜杠」重定向,端口自然不丢。书签直接存这个完整地址就行。但这是治标,下面三个场景才是治本。
场景1:SpringBoot(最常见)
application.yml 加一行,让重定向走相对路径:
server:
tomcat:
use-relative-redirects: true
作用:不再生成 http://ip/path/ 这种绝对 URL,跳转变为 /your-app/,浏览器自动沿用当前 IP + 端口,端口不会丢。老版本用 properties 写法:
server.tomcat.use-relative-redirects=true
场景2:原生 Tomcat(war 包部署)
改 conf/server.xml 里的 Connector,补一个 proxyPort,写公网对外端口 17080,不是内网端口:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
proxyPort="17080" />
改完重启 Tomcat 即可。Tomcat 会拿 proxyPort 拼绝对地址,端口就回来了。
场景3:代码里手动 sendRedirect
千万别写死绝对地址。下面这种 ❌ 写法,公网一访问端口就丢:
// ❌ 绝对地址,端口会丢
response.sendRedirect("http://1.2.3.4/your-app/");
改成 ✅ 相对路径,框架自动带上当前上下文和端口:
// ✅ 相对路径,沿用当前 IP + 端口
response.sendRedirect("/your-app/");
🚨 凯哥的踩坑提醒:浏览器会永久缓存 301,改完配置一定要开无痕窗口测;另外确认路由器只是单纯的虚拟服务器/端口转发,别顺手开了 DMZ、防火墙 HTTP 劫持、强制门户那类功能。最稳的验证:内网直接用内网 IP + 内部端口访问,如果内网也跳丢端口,那就是应用本身行为;内网正常、只有外网异常,才是代理端口识别问题。

结束语
大家好,我是凯哥Java(kaigejava),乐于分享技术文章,欢迎大家关注"凯哥Java",及时了解更多。让我们一起学Java。也欢迎大家有事没事就来和凯哥聊聊~~~
如果你最近在搞路由器端口转发、SpringBoot 或 Tomcat 外网部署,遇到「一访问就跳转到没端口的地址」这种坑,先 curl -I 抓一眼 Location,照上面 3 种场景对症改一行配置,比对着路由器瞎调一天都管用。
路由器端口转发访问打不开排查
端口转发301重定向丢端口原因
SpringBoot use-relative-redirects 配置
Tomcat proxyPort 外网端口设置
sendRedirect 相对路径写法
路由器端口转发301跳转丢端口解决方案
Tomcat proxyPort公网端口配置实战
SpringBoot相对重定向外网部署指南
作者:凯哥Java
类型:原创
标签:路由器端口转发、SpringBoot重定向、Tomcat配置、端口丢失
原创声明:本文原创发表于「凯哥Java」,转载请注明出处。