curl 网络排障实战:从 DNS 解析到 HTTPS 握手
前言
在 Linux 服务器上部署应用时,经常会遇到网站访问超时、接口请求失败或者 HTTPS 连接异常的问题。
这类问题不能简单地归结为“网络不通”。一次 HTTPS 请求通常需要经历域名解析、TCP 连接、TLS 握手和 HTTP 数据传输等阶段,不同阶段失败,对应的排查方向也不一样。
curl 不仅能发送 HTTP 请求,还可以显示连接详情、响应状态和各阶段耗时。下面介绍几个比较实用的排查方法。
一、先发起一次完整请求
首先设置目标域名,后续命令均使用这个变量:
DOMAIN="替换成需要测试的域名"
例如要检查一个 HTTPS 网站,可以执行:
curl -v --connect-timeout 5 --max-time 15 "https://$DOMAIN/"
其中:
-v:显示详细连接信息。--connect-timeout 5:限制建立连接阶段的等待时间。--max-time 15:限制整个请求允许的最长时间。
在输出中可以看到 curl 使用的 IP 地址、连接过程、TLS 相关信息以及 HTTP 响应头。
如果遇到错误,先观察失败发生在哪个阶段,不要直接判断为服务器故障。
二、排查 DNS 解析问题
如果出现:
Could not resolve host
通常表示 curl 没有成功解析目标主机名。
可以先用系统命令查看解析情况:
getent ahosts "$DOMAIN"
在支持该命令的 Linux 系统中,它可以通过系统名称解析机制查询主机地址。
如果解析失败,可以检查:
- 域名是否输入正确。
- 系统使用了哪个 DNS 解析服务。
- DNS 服务器是否能够访问。
- 是否存在本地解析配置问题。
还要注意,DNS 解析成功只能说明获得了地址,并不能证明目标服务器能够建立 TCP 连接。
三、检查 TCP 连接
如果已经解析到了 IP,但连接依然失败,可以关注 curl 的错误信息。
例如:
Failed to connect
Connection refused
Connection refused 通常表示目标地址没有接受此次 TCP 连接,可能是服务没有监听对应端口,也可能是防火墙主动拒绝。
如果一直超时,则可能涉及网络路由、防火墙丢弃、服务器不可达等问题。
可以指定 IPv4 或 IPv6 进行对比:
curl -4 -v --connect-timeout 5 "https://$DOMAIN/"
curl -6 -v --connect-timeout 5 "https://$DOMAIN/"
如果 IPv4 正常、IPv6 失败,就应该进一步检查 AAAA 记录、IPv6 路由及服务监听情况。
不过,不能仅凭一次连接失败就断定是哪台网络设备造成的,需要结合具体报错和网络环境判断。
四、排查 TLS 握手和证书问题
HTTPS 在建立 TCP 连接后,还需要进行 TLS 握手。
如果出现:
SSL certificate problem
就需要检查证书链、证书有效期、系统信任的 CA,以及访问域名是否与证书匹配。
另一个常见问题是使用 IP 地址直接访问 HTTPS 网站。
对于使用虚拟主机的网站,直接访问 IP 可能无法匹配正确的域名、SNI 或证书。
如果想指定连接的目标 IP,同时保留正常的域名访问方式,可以使用:
IP="替换成目标服务器IP"
curl -v --resolve "$DOMAIN:443:$IP" "https://$DOMAIN/"
--resolve 会为指定的主机名和端口提供临时地址映射。这对于排查 DNS 解析结果异常、测试不同服务器入口非常方便。
需要注意,它改变的是连接目标地址,并不会自动忽略 HTTPS 证书验证。
有些教程会使用 -k 跳过证书检查,但这样会降低连接安全性。生产环境不应把关闭证书验证当作正常解决方案。
五、查看 HTTP 状态码
如果 DNS、TCP 和 TLS 阶段都成功了,还需要检查应用层返回了什么。
可以执行:
curl -sS -o /dev/null -w 'HTTP状态码: %{http_code}\n' "https://$DOMAIN/"
其中:
-sS:减少普通进度信息,同时保留错误提示。-o /dev/null:不在终端输出响应正文。-w:自定义请求完成后的统计信息。
常见 HTTP 状态码包括:
| 状态码 | 常见含义 |
|---|---|
| 200 | 请求成功 |
| 301 / 302 | 请求被重定向 |
| 403 | 服务器拒绝访问 |
| 404 | 请求的资源不存在 |
| 500 | 服务器发生内部错误 |
| 502 | 网关收到了无效的上游响应 |
| 504 | 网关等待上游响应超时 |
需要注意,返回 403 或 404 并不代表网络没有连接成功。它们说明已经获得了 HTTP 响应,只是请求没有得到预期结果。
另外,如果 curl 在收到 HTTP 响应前就失败,状态码可能显示为 000,这不是正式的 HTTP 状态码。
六、查看请求各阶段耗时
curl 的 -w 功能还可以用于分析请求慢在哪个阶段。
例如:
curl -sS -o /dev/null \
-w 'DNS: %{time_namelookup}s\nTCP: %{time_connect}s\nTLS: %{time_appconnect}s\n首字节: %{time_starttransfer}s\n总耗时: %{time_total}s\n' \
"https://$DOMAIN/"
这些字段的含义分别为:
time_namelookup:从请求开始到名称解析完成的耗时。time_connect:从开始到 TCP 连接建立完成的累计耗时。time_appconnect:从开始到 TLS 等应用层握手完成的累计耗时。time_starttransfer:从开始到收到第一个响应字节的累计耗时。time_total:整个请求的总耗时。
这里有一个容易理解错的地方:这些时间大多是从请求开始计算的累计值,并不是各阶段独立耗时。
例如,想计算 TCP 连接阶段的近似耗时,可以用 time_connect 减去 time_namelookup。
想估算 TLS 握手耗时,可以用 time_appconnect 减去 time_connect。
如果通过 HTTP 代理访问,这些计时值还可能包含代理连接相关操作,不能直接当作客户端到最终目标服务器的独立网络延迟。
七、检查是不是代理影响了请求
服务器或终端中如果设置了代理环境变量,curl 可能会自动使用这些代理。
可以先查看:
env | grep -i proxy
如果希望临时绕过代理进行对照测试,可以使用:
curl --noproxy '*' -v "https://$DOMAIN/"
这样可以帮助区分代理连接问题和直连问题。
不过,--noproxy 只影响 curl 自身的代理选择,无法绕过系统网络层已经存在的透明代理或其他转发规则。
如果直连正常、使用代理失败,就应进一步检查代理服务器、认证和转发配置。
八、一个简单的排查顺序
遇到 HTTPS 请求失败时,可以按下面的顺序排查:
第一步,使用 curl -v 查看具体报错,判断是否已经解析到目标 IP。
第二步,如果解析失败,检查 DNS 配置;如果解析成功但连接失败,检查 TCP 连接及防火墙。
第三步,如果 TCP 已连接但 HTTPS 失败,重点检查 TLS 握手、SNI 和证书。
第四步,如果已经收到 HTTP 响应,就根据状态码和服务器日志排查应用层问题。
最后,如果只是访问慢而不是完全失败,可以使用 -w 查看各阶段累计耗时,进一步缩小排查范围。
总结
curl 不只是一个下载工具,也非常适合排查 Linux 服务器上的网络连接问题。
最常用的几个参数包括:
-v:显示详细连接信息。-4、-6:分别测试 IPv4 和 IPv6。--resolve:指定域名对应的连接地址。--connect-timeout:限制建立连接的等待时间。-w:输出状态码和请求耗时。--noproxy:临时排除代理干扰。
实际排障时,最重要的不是一次执行多少命令,而是先判断失败发生在 DNS、TCP、TLS 还是 HTTP 阶段,再针对对应环节检查。
- 点赞
- 收藏
- 关注作者
评论(0)