最快的办法是 curl -s -o /dev/null -w '%{time_total}\n' https://api.example.com/,它只打印总耗时,别的都不输出。这一个数字说明不了延迟到底出在 DNS、网络、TLS 还是服务器本身——要弄清楚,得把请求拆成几个阶段。下面是五个数字,而不是一个,以及每个数字该怎么用。
1. 这次请求到底花了多久
$ clai 这个地址响应需要几秒→ curl -s -o /dev/null -w '%{time_total}\n' https://cliai.tech/1.244094
-o /dev/null 丢弃响应体,-s 隐藏进度条,-w 只打印你要的内容。现在有了一个数字,但它什么也解释不了。
2. 按阶段拆分耗时
$ clai 按阶段拆分响应时间:dns、连接、tls、首字节→ curl -s -o /dev/null -w 'dns: %{time_namelookup}\nconnect: %{time_connect}\ntls: %{time_appconnect}\nttfb: %{time_starttransfer}\ntotal: %{time_total}\n' https://cliai.tech/dns: 0.000782connect: 0.299098tls: 0.414729ttfb: 1.124750total: 1.244094
这些数值是累积的,不是相互独立的——真正有意义的是它们之间的差值。DNS 用了 0.0008 秒,建立 TCP 连接用了 0.298 秒,TLS 握手用了 0.116 秒,而从 TLS 就绪到收到首字节用了 0.71 秒——这是服务器在处理请求的时间。如果有问题,多半就在这里。
3. 看差值,而不是绝对数字
time_namelookup 超过 0.1 秒,说明是解析器或缓存冷启动的问题。connect - namelookup 是到服务器的网络延迟,大致相当于往返 ping 的一半。starttransfer - appconnect 是服务器处理请求花的时间。total - starttransfer 是body 传输时间,取决于响应体大小。
4. 状态码到底是不是 200
$ clai 显示耗时、状态码和响应体大小→ curl -s -o /dev/null -w 'code: %{http_code} size: %{size_download} total: %{time_total}\n' https://cliai.tech/code: 200
没有状态码的耗时数字毫无意义——很快返回的 500 不代表一切正常。完整的变量列表见 man curl 的 WRITE-OUT VARIABLES 一节。
5. 测一次不够
$ clai 连续测五次响应时间→ for i in $(seq 5); do curl -s -o /dev/null -w '%{time_total}\n' https://cliai.tech/; done
单次测量说明不了任何问题。第一次请求几乎总是更慢,因为 DNS 缓存是冷的、连接也要重新建立。要看的是多次测量之间的波动,而不是第一个数字。
6. 把格式存进文件
$ clai 把测量格式保存到文件并复用→ curl -s -o /dev/null -w @curl-format.txt https://cliai.tech/
-w @文件 从文件读取格式,长长的内联字符串就不再碍事。这类文件通常放在仓库里,和其他检查脚本放在一起。
常见坑
- 数值是累积的。
time_appconnect已经把 DNS 和连接时间算进去了。要减去上一阶段的值,否则会误以为 TLS 花了半秒,其实那是它之前所有阶段的总和。 - 纯 HTTP 下
time_appconnect是零。 没有 TLS 就没有这个阶段,这里的零不是测量错误。 - curl 只测量单次请求,不是性能。 要测负载得用
hey、wrk或k6。curl 回答的是"时间花在哪了",不是"能扛住多少流量"。
相关问题
什么是 TTFB? 首字节时间,也就是输出里的 time_starttransfer。它通常最能反映后端速度。
为什么第一次请求总是更慢? DNS 缓存是冷的,还要建立 TCP 连接和 TLS 握手。通过 keep-alive 复用连接的请求会跳过这三步。
怎么单独测 DNS? 单独看 %{time_namelookup},或者用 dig +stats,它会把解析时间和其他部分分开显示。
相关阅读
别再死记硬背 curl 的 -w 格式了——描述你想测量什么,CliAI 帮你写命令。一行命令安装。