---
title: "用 curl 定位接口问题：-w 的五个时间戳比 -v 更有用"
date: 2026-11-10
slug: curl-timing-troubleshooting
canonical: https://kernelranch.com/blog/2026/11/curl-timing-troubleshooting
markdown_url: https://kernelranch.com/blog/2026/11/curl-timing-troubleshooting.md
tags: ["curl", "http", "troubleshooting", "cheatsheet"]
---接口慢了，第一反应常是加日志。其实一条 `curl -w` 就能把时间拆开，看出慢在 DNS、连接、握手，还是服务端。

## 1. 一条命令看五段

```bash
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. 三个常用组合

```bash
# 只看状态码（脚本里最常用）
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` 这些参数全报错。判断方法：

```powershell
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` 的差异。
