Skip to content

一次网络请求的完整旅程 ​

当请求失败时,“网络有问题”的范围太大,无法指导排查。更快的方法是确定最后一个明确成功的阶段,以及第一个没有成功的阶段。

URL 之外的路径 ​

text
应用程序
  → 名称解析
  → 本地路由或 TUN 设备
  → 可选代理
  → TCP 连接
  → TLS 握手
  → HTTP 交换
  → 反向代理
  → 应用服务
  → 数据库或下游服务

页面上的主机名不一定是真实连接目标。代理可能接收主机名并负责建立远程连接;TUN 客户端也可能返回合成地址,在操作系统真正访问公网前拦截流量。

1. 名称解析 ​

记录解析结果以及由谁生成。普通公网地址、私网地址和 Fake-IP 网段中的合成地址代表不同路径。

需要回答:

  • 应用使用系统 Resolver、DNS-over-HTTPS,还是代理的 Resolver?
  • 解析结果是否来自缓存?
  • 代理收到的是主机名,还是已经解析的地址?

修改 HTTPS_PROXY 等环境变量并不能改变 TUN 路由或 DNS 拦截规则。

2. 路由和代理选择 ​

connect() 成功只说明有组件接受了 Socket。存在本地隧道时,这个组件可能是隧道进程,而不是远程服务器。

应当同时收集两类信息:

  • 操作系统选择的路由和网络接口;
  • 代理或隧道的连接记录与命中规则。

如果策略要求仅对一个目标直连,必须验证运行时规则命中。只修改配置文件而不确认运行进程已经重新加载,并不能证明路径已经改变。

3. TCP 连接 ​

TCP 只建立字节流,不负责认证服务器,也不能证明预期协议正在响应。

nc -vz host 5432 可能通过拦截代理报告成功,即使服务器完全没有 PostgreSQL Listener。应发送协议握手,或直接检查服务器监听端口,才能判断数据库是否暴露。

4. TLS 握手 ​

TLS 包含三个独立结论:

  1. 成功协商加密会话;
  2. 证书链受信任;
  3. 证书身份与主机名或 IP 匹配。

关闭校验会隐藏证据并引入新的安全问题。正确做法是检查证书、SNI、信任库和具体握手错误。

5. HTTP 与应用语义 ​

HTTP 响应只证明有一个支持 HTTP 的组件进行了回复。它可能是代理错误页、反向代理兜底页面,也可能是目标 API。

至少验证:

  • 状态码;
  • Content-Type 和稳定的响应字段;
  • 可用时检查 Request ID 或服务端身份;
  • 业务相关的数量和边界条件。

对于数据 API,HTTP 200 是验证的开始,而不是结束。

证据表 ​

阶段有力证据尚不能证明
DNSResolver 与返回地址实际使用的路由
路由网络接口与代理命中规则远程协议已接受请求
TCP完成三次握手服务器身份
TLS证书验证与加密会话应用行为正确
HTTP预期状态和 Schema数据完整
应用与源数据比较边界条件其他接口也正常

排查顺序 ​

  1. 记录完整命令、URL 和时间。
  2. 检查阻塞进程及其当前连接目标。
  3. 验证解析结果和路由选择。
  4. 测试真实协议,而不只测试 TCP 可达性。
  5. 对照客户端证据、服务端监听和日志。
  6. 每次只改变一个作用域明确的变量,然后重复同一测试。

这个顺序可以把模糊的网络问题缩小为一个明确的阶段失败。

所有文章均为原创,以理解为目标。