cURL 的 -v、-i、-I、-s 参数有什么区别?
cURL 是后端开发和运维中最常用的命令行工具之一,而 -v、-i、-I、-s 这四个参数控制着输出的内容和格式。很多人混用它们,实际上它们的输出目标、请求方式和适用场景完全不同。
一张图看清区别
| 参数 | 全称 | 请求方法 | 输出内容 | 输出目标 |
|---|---|---|---|---|
-v | --verbose | 不改变 | 连接过程 + 请求头 + 响应头 | stderr |
-i | --include | 不改变 | 响应头 + 响应体 | stdout |
-I | --head | HEAD | 仅响应头 | stdout |
-s | --silent | 不改变 | 仅响应体(无进度条) | stdout |
关键区别:
-v的输出写入 stderr,其余三个写入 stdout。这意味着-v不会干扰管道操作,而-i和-I的响应头会混入 stdout 数据流。
逐个拆解
-v:看懂完整的通信过程
bashcurl -v https://api.example.com
输出长这样:
shell* Trying 93.184.216.34:443... * Connected to api.example.com (93.184.216.34) port 443 * SSL connection using TLS_AES_256_GCM_SHA384 > GET / HTTP/1.1 > Host: api.example.com > User-Agent: curl/8.1.2 > Accept: */* > < HTTP/1.1 200 OK < Content-Type: application/json < Content-Length: 42 < {"status":"ok"}
输出符号的含义:
*开头 —— 连接和 TLS 握手信息>开头 —— 发送给服务器的请求头<开头 —— 服务器返回的响应头
为什么 -v 写入 stderr 而不是 stdout? 这是 curl 的设计哲学:stdout 留给实际数据(响应体),stderr 留给诊断信息。所以你可以这样用:
bash# 调试信息存文件,响应体正常输出 curl -v https://api.example.com 2>debug.log # 管道不会被打断 curl -v https://api.example.com 2>/dev/null | jq .status
-i:响应头和响应体一起拿
bashcurl -i https://api.example.com
输出:
shellHTTP/1.1 200 OK Content-Type: application/json Content-Length: 42 Date: Mon, 01 Mar 2026 10:00:00 GMT {"status":"ok"}
响应头和响应体之间用一个空行分隔。-i 不改变请求方法,该发 GET 还是 GET,该发 POST 还是 POST,只是把响应头也一并输出。
注意:因为响应头混入了 stdout,直接管道给 jq 会解析失败。解决办法:
bash# 用 -D - 把响应头写到 stderr,响应体单独给 jq curl -s -D - https://api.example.com 2>/dev/null | jq .
-I:只看响应头,不发请求体
bashcurl -I https://api.example.com
输出:
shellHTTP/1.1 200 OK Content-Type: application/json Content-Length: 42 Date: Mon, 01 Mar 2026 10:00:00 GMT ETag: "abc123" Cache-Control: max-age=3600
-I 会把请求方法改成 HEAD。大多数服务器对 HEAD 请求和 GET 请求返回相同的响应头,但不是所有:
- 有些 CDN 对 HEAD 请求返回的
Content-Length可能为 0 - 某些 API 网关对 HEAD 和 GET 的路由规则不同
- 少数服务器直接拒绝 HEAD 请求
如果需要 GET 请求的响应头,用这个代替:
bashcurl -s -D - -o /dev/null https://api.example.com
-s:安静干活,只出结果
bash# 不显示进度条,只输出响应体 curl -s https://api.example.com
-s 关闭进度条和错误信息,但不会关闭响应体输出。在脚本里特别有用:
bash# 获取数据并解析 response=$(curl -s https://api.example.com/users) echo "$response" | jq ".[] | .name"
-s 的坑:静默模式下连错误信息也被吞了。网络超时、DNS 解析失败都不会有任何提示。所以实际使用中,-s 几乎总是和 -S 搭配:
bash# 静默但保留错误输出 curl -sS https://api.example.com
常见组合技巧
bash# 检查 HTTP 状态码(脚本健康检查) curl -s -o /dev/null -w "%{http_code}" https://api.example.com # 调试 SSL 证书问题 curl -v https://api.example.com 2>&1 | grep -E "SSL|TLS|certificate" # 静默拿响应头(实际发 GET 请求) curl -s -D - -o /dev/null https://api.example.com # 完整调试 + 保存日志 curl -v https://api.example.com -o response.json 2>debug.log # 检查 CDN 缓存是否命中 curl -I -s https://cdn.example.com/image.jpg | grep -i "x-cache"
面试追问方向
Q: -v 和 -i 都能看到响应头,有什么本质区别?
A: 三个关键区别:(1)-v 同时显示请求头和响应头,-i 只显示响应头;(2)-v 还包含连接过程(DNS、TLS 握手),-i 只包含最终响应;(3)-v 写入 stderr,-i 写入 stdout,管道处理时行为完全不同。
Q: 为什么 curl -I 有时候拿不到正确的 Content-Length?
A: 因为 -I 发送的是 HEAD 请求,有些服务器对 HEAD 请求返回的 Content-Length 为 0 或者不返回该字段。如果需要 GET 请求的真实 Content-Length,应该用 curl -s -D - -o /dev/null 代替。
Q: -sS 组合是什么意思?为什么不直接用 -s?
A: -s 关闭了进度条和所有错误输出,包括网络超时、连接拒绝等重要信息。-S(--show-error)在 -s 模式下重新启用错误输出。脚本中几乎总是需要 -sS 而非单独 -s,否则故障排查时完全不知道请求为什么失败。
速查表
| 你想做什么 | 用什么参数 |
|---|---|
| 排查请求为什么没发出去 | -v |
| 看服务器返回了什么响应头 | -i 或 -D - |
| 只检查状态码或缓存头 | -I 或 -I -s |
| 脚本里安静拿数据 | -sS |
| 获取 HTTP 状态码 | -s -o /dev/null -w "%{http_code}" |
| 保存调试日志 | -v 2>debug.log |