用 curl 定位接口问题:-w 的五个时间戳比 -v 更有用
接口慢了,第一反应常是加日志。其实一条 curl -w 就能把时间拆开,看出慢在 DNS、连接、握手,还是服务端。
1. 一条命令看五段
curl -s -o /dev/null -w "dns=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} ttfb=%{time_starttransfer} total=%{time_total} code=%{http_code}\n" https://example.com/
真实输出(本机访问 quote.kernelranch.com/2fa,2026-11-10):
dns=0.278397 connect=0.538940 tls=0.821185 ttfb=1.116068 total=1.704376 code=200
五段的关系是包含的:connect 包含 dns,tls 包含前两者,ttfb 包含全部前置动作,total 是收完响应体的时间。要做减法看增量:
| 增量 | 计算 | 慢在这里说明什么 |
|---|---|---|
| DNS | dns | 解析慢,检查递归解析器、DoH、或域名本身 |
| TCP 建连 | connect - dns | 网络或服务端 accept 慢 |
| TLS 握手 | tls - connect | 证书链、OCSP、TLS 版本协商 |
| 服务端处理 | ttfb - tls | 应用逻辑、数据库、上游调用 |
| 传输 | total - ttfb | 响应体大或带宽不足 |
上面那次的增量是:DNS 0.28s、TCP 0.26s、TLS 0.28s、服务端 0.29s、传输 0.59s。四段几乎平均,说明不是单点问题,而是链路整体偏慢——这种时候换机房比调代码有用。
2. 退出码比状态码更早暴露问题
code=000 表示没有拿到 HTTP 响应,具体原因看退出码:
| 退出码 | 含义 | 典型原因 |
|---|---|---|
| 6 | 无法解析主机 | 域名拼错、DNS 不可用 |
| 7 | 连接被拒 | 端口没监听、防火墙 |
| 28 | 超时 | 对端不响应或太慢 |
| 35 | TLS 握手失败 | 证书、协议版本、SNI |
实测访问一个不存在的域名:
code=000 dns=0.000000
exit=6
DNS 耗时为 0 且退出码 6,说明请求根本没发出去。
3. 三个常用组合
# 只看状态码(脚本里最常用)
curl -s -o /dev/null -w "%{http_code}\n" https://example.com/
# 限制总时长,避免脚本挂死
curl -s --max-time 5 -o /dev/null -w "%{http_code}\n" https://example.com/
# 指定解析结果,绕过本地 DNS 或验证新 IP
curl -s --resolve example.com:443:203.0.113.10 https://example.com/
--resolve 在切换 DNS、验证新服务器时特别有用:不用改 hosts,也不用等缓存过期。
4. 两个坑
PowerShell 里的 curl 可能不是 curl。Windows PowerShell 5.x 把 curl 别名指向 Invoke-WebRequest,于是 -w、-o 这些参数全报错。判断方法:
Get-Command curl | Select-Object Name, CommandType, Source
要真 curl 就写 curl.exe。本机实测 curl.exe -s -o NUL -w ... 正常,-o /dev/null 在 Windows 上要换成 NUL。
-w 里的变量要加百分号并转义。在 bash 里 %{time_total} 直接可用;在 Windows 的 cmd 里不需要转义,但在 PowerShell 双引号中 % 没有特殊含义,可以照写;如果放进 bash -c,记得单引号包裹。
小结
-v 告诉你请求和响应长什么样,-w 告诉你时间花在哪。排查慢接口先看 -w 的增量,再看 -v 的握手细节,最后才去翻服务端日志。
一个容易忽略的细节:total - ttfb 如果占比很高,往往不是服务端慢,而是响应体太大或客户端带宽不够。这时候优化 SQL 是白费功夫。
数据来源与检索时间
检索时间 2026-11-10。计时数据为本机实测。
| 来源 | URL | 对应数据 |
|---|---|---|
| curl 手册《--write-out》 | https://curl.se/docs/manpage.html | time_namelookup、time_connect、time_appconnect、time_starttransfer、time_total 的定义与包含关系;--resolve 语义 |
| curl 退出码说明 | https://curl.se/docs/manpage.html#EXITCODES | 退出码 6/7/28/35 的含义 |
| Microsoft Learn《about_Aliases》 | https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_aliases | Windows PowerShell 中 curl 别名为 Invoke-WebRequest 的行为 |
核验说明
- 第 1、2 节的计时输出与退出码均为本机执行结果(curl 8.x,Windows 11)。
- 未做:没有在丢包、高延迟链路上验证各段耗时分布;没有测试 HTTP/2 与 HTTP/3 下
time_appconnect的差异。