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. 每次只改变一个作用域明确的变量,然后重复同一测试。

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

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