5月28日 01:54

cURL 的 -v、-i、-I、-s 参数有什么区别?

cURL 是后端开发和运维中最常用的命令行工具之一,而 -v-i-I-s 这四个参数控制着输出的内容和格式。很多人混用它们,实际上它们的输出目标、请求方式和适用场景完全不同。

一张图看清区别

参数全称请求方法输出内容输出目标
-v--verbose不改变连接过程 + 请求头 + 响应头stderr
-i--include不改变响应头 + 响应体stdout
-I--headHEAD仅响应头stdout
-s--silent不改变仅响应体(无进度条)stdout

关键区别:-v 的输出写入 stderr,其余三个写入 stdout。这意味着 -v 不会干扰管道操作,而 -i-I 的响应头会混入 stdout 数据流。

逐个拆解

-v:看懂完整的通信过程

bash
curl -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:响应头和响应体一起拿

bash
curl -i https://api.example.com

输出:

shell
HTTP/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:只看响应头,不发请求体

bash
curl -I https://api.example.com

输出:

shell
HTTP/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 请求的响应头,用这个代替:

bash
curl -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
标签:cURL