企业 VPN 下应用请求失败而浏览器正常
浏览器能打开站点,某个应用却坏了。按这个顺序排查它继承的代理、端口策略、原始 TCP 重置和载荷大小限制。
你在浏览器里打开内部门户,页面正常加载。你运行调用同一主机的应用,它却失败,报错信息里连是哪一层都不提。隧道既然能承载浏览器,隧道就不是首要嫌疑。请求与服务之间有四种东西,各自留下不同痕迹。下面是我走的顺序:从那款应用实际发出的请求开始,而不是从 VPN 客户端的设置页开始;先看清事实,再谈改动。
先看应用实际发出的请求
在动配置之前,让应用自己说出它做了什么,别靠猜,也别先改隧道。显式关掉代理抓一次请求,再加一次简单的端口测试,你就得到两条基线,后面的步骤都拿它们作对照。如果关掉代理后请求成功,四层里已经排掉三层,剩下那层再慢慢查也不迟。
env | grep -i proxy # Linux/macOS
netsh winhttp show proxy # Windows, machine-wide
curl -sv --noproxy '*' https://svc.internal/
nc -vz svc.internal 8080把最后两条命令指向同一个目标,看它们在哪里分岔。浏览器通、curl 也通、应用不通,问题就被压缩到应用自己加的东西上:代理、传输方式,或者消息大小。
应用继承了一个没人配过的代理
多数 HTTP 栈默认从操作系统读取代理配置。企业 VPN 客户端常把代理装进自己的接入配置文件里,于是请求从一个开发者在代码里从未提及的代理走出去。.NET 的默认处理器读 IE/WinHTTP 设置;Java 读 -Dhttp.proxyHost;Node 在内置代理支持出现之前什么也没有,直到某个库补上。失败很少是干脆的拒绝,人们这才开始怀疑服务器。
测试只花一次请求:在一个处理器上显式关掉代理,然后对比。
var handler = new HttpClientHandler { UseProxy = false };
using var client = new HttpClient(handler);如果这样能通,修复该落在应用的配置里,而不是隧道里。项目里有几种运行时就把审查做几遍,因为它们各读各的来源,坏的可能只有一个,别把一处的问题当成全局结论。
你选的端口不是策略允许的端口
主机被路由,不等于服务被放行。企业策略通常只放行出站的 Web 端口,其余一律丢弃,所以 8080 或 1883 上的服务根本到不了,而 443 一切正常。浏览器在这里证明不了什么:它按定义就用 443。
把同一服务发布到 443 后面,先用名字访问到它,再考虑申请例外。如果例外确实必要,就把它限定在一个源网段和一个目标上,并当成服务定义的一部分,而不是某个人的私人绕行方案。
被路径重置的原始 TCP
长连接的原始 TCP 是最容易让人误判的一层。允许 Web 流量的路径,照样可能 重置或改写异常的出站 TCP,客户端报出的套接字错误读起来像服务中断。消息类和事件类服务通常会为这种网络专门提供 WebSocket 传输,切换它是客户端选项,不是改隧道。
换传输方式,重测,同一次运行里别的都不动。这个单变量测试会告诉你重置来自路径还是来自服务。
只在大载荷时才断的连接
请求先成功,约一秒后死掉,而且只有请求体大时才死,这说明中间某处有大小上限。一个统计消息字节的中间设备可以在传输中途把连接丢掉,客户端报的是异常关闭,而不是超时,这一点很容易被当成服务端崩溃。
在应用层把载荷分块。这和 MTU 的工作要分开:调小隧道的包长,帮助的是普通 TCP 会话卡在固定字节数上的情形;对中间设备认为过大的消息,它一点用也没有,两件事别混在一次改动里。
一遍分清这四层
三个观察能定掉大多数情况。失败是立刻发生,还是只在大请求体时发生?关掉代理后同样的请求能通吗?换端口或换传输方式,结果会跟着变吗?先把答案写下来再改下一处,因为企业 VPN 加继承的代理加应用默认值,一下就给你三个都说得通的成因。
每次只动一个变量,并记下你用的目标主机。没有这条基线,下一个人只会把四步从头再走一遍,还得重新猜一次当初的结论。