curl -i vs curl -I vs curl -v:三个让人混淆的标志位

如果你搜过「怎么用 curl 只拿响应头?」,一定见过下面这团乱麻:

  • 一个 Stack Overflow 答案说 curl -I
  • 另一个说 curl -i
  • 第三个说 curl -v
  • 第四个推荐 curl -X HEAD -i(这是错的

它们做的是不同的事。本文基于 curl 8.21.1(截至 2026 年 7 月当前版本)、官方 man page、以及 curl 创始人 Daniel Stenberg 本人在 Stack Overflow 上的回答,把这三个标志位讲清楚。

TL;DR —— 一秒钟答案

标志 长格式 拿到什么 HTTP 方法
-i --show-headers 响应头 + body 混在同一输出流 GET
-I --head 只有响应头,不要 body HEAD
-v --verbose 请求行 + 响应头 + TLS + 计时,输出到 stderr GET

只想拿响应头:用 -I想同时拿响应头和 body:用 -i调试连接问题:用 -v

详细对比

-i / --show-headers:把响应头插进输出

让 curl 把响应头放到正常输出流的最前面。body 还是会下载 —— 区别只是你能先看到头。

Bash
$ curl -i https://example.com
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 1256
Date: Tue, 14 Jul 2026 12:00:00 GMT
Server: ECS (sec/9743)
Accept-Ranges: bytes
Age: 423741
Cache-Control: max-age=604800
Etag: \"3147526947+gzip\"
Expires: Tue, 21 Jul 2026 12:00:00 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Vary: Accept-Encoding
X-Cache: HIT

<!doctype html>
<html>
<head>...</head>
<body>
... 完整 body 在这里 ...
</body>
</html>

全有:响应头 + body。适合调试单个请求、想同时看元数据和实际内容。

注意:curl 8.10.0(2024 年 11 月发布)把长格式从 --include 改名成了 --show-headers。旧的 --include 还能用但已 deprecated:

Bash
# 都能用,但 2026 年第二个是规范名
curl -i https://example.com
curl --show-headers https://example.com

-I / --head:只取响应头

发一个真正的 HTTP HEAD 请求 —— 服务器只回响应头,没有 body。更快、更省带宽,是探测 URL 状态而不用下载任何内容的正确工具。

Bash
$ curl -I https://example.com
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 1256
Date: Tue, 14 Jul 2026 12:00:00 GMT
...

输出和 -i 一样,但没有 body。响应头一到连接就关。

彩蛋:对 ftp://file:// URL,-I 只显示文件大小和最后修改时间 —— 这在 shell 脚本里很方便:

Bash
$ curl -I https://releases.ubuntu.com/24.04/ubuntu-24.04-desktop-amd64.iso
HTTP/1.1 200 OK
Content-Length: 5959565824
Last-Modified: Thu, 25 Apr 2024 18:42:31 GMT
...

这就是 ISO 文件的字节数和发布时间 —— 写校验脚本或者「这文件这周变了吗?」检查很顺手。

-v / --verbose:展示完整对话

-v 是调试用的,不是给你解析的。它打印到 stderr

  • * —— 信息消息(DNS 查询、TCP 连接、TLS 握手等)
  • > —— curl 发出去的字节(请求行、响应头、body)
  • < —— curl 收到的字节(响应行、响应头、body)

Bash
$ curl -v https://example.com 2>&1 | head -20
* Trying 93.184.216.34:443...
* Connected to example.com (93.184.216.34) port 443
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, FINISHED (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, FINISHED (20):
* SSL connection using TLS_AES_128_GCM_SHA256
* Server certificate:
*  subject: CN=example.com
*  start date: Jun  3 00:00:00 2026 GMT
*  expire date: Jun  3 23:59:59 2027 GMT
*  issuer: C=US; O=DigiCert Inc; CN=DigiCert Global G2 TLS RSA SHA256 2020 CA1
...
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/8.21.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
...

可以叠加详细度:

  • -vv —— 加时间戳和 trace ID
  • -vvv —— 同时打印实际传输内容(完整请求和响应 body)
  • -vvvv —— 启用所有网络组件的 trace

man page 里的隐私警告:verbose 输出可能包含用户名、凭据、bearer token、密钥 payload 内容。粘贴 -v 输出到聊天或 GitHub issue 之前先想清楚。

何时该用哪个

-I,当你…

想要探测一个 URL 又不下载 body。常见场景:

Bash
# 站点还活着吗?
curl -I https://example.com | head -1
# HTTP/1.1 200 OK

# 短链最终跳到哪里?
curl -IL https://bit.ly/example
# HTTP/1.1 301 Moved Permanently
# Location: https://example.com/full-path
# HTTP/1.1 200 OK

# 这个下载文件多大?
curl -I https://releases.example.com/big-file.tar.gz | grep -i content-length

# 这个 URL 是什么文件类型?
curl -I https://example.com/mystery-file | grep -i content-type

-i,当你…

看单个请求的响应头 + body —— 通常在调试 API 调用或单次下载时:

Bash
# 调试 JSON API: 同时看响应头和解析后的 body
curl -i https://api.github.com/repos/torvalds/linux | head -30

# 调试登录时检查 Set-Cookie 头
curl -i -c cookies.txt https://example.com/login

# 验证 gzip 开启: 查 Content-Encoding
curl -i -H \"Accept-Encoding: gzip\" https://example.com/big-file

-v,当你…

正在调试连接问题 —— TLS 错误、超时、意外重定向、DNS 问题、代理问题:

Bash
# SSL 握手为什么失败?
curl -v https://expired.badssl.com/ 2>&1 | grep -A 3 \"TLS|certificate\"

# 实际用的是哪个代理?
curl -v https://example.com 2>&1 | grep -i \"proxy|connect\"

# 追踪 DNS 解析路径
curl -v https://example.com 2>&1 | grep -A 2 \"Trying|Connected\"

-X HEAD -i 这个反模式

这是 2010 年就错但至今还在流传的 Stack Overflow 答案:

Bash
# 别这么写
curl -X HEAD -i https://example.com

本意是「发 HEAD、再显示响应头」。但:

  • -X HEAD 把默认 GET 覆盖成 HEAD
  • -i 让 curl 显示响应头
  • 真正的 HEAD 响应没有 body,但 -i 让 curl 傻等 Content-Length 字节
  • 结果:curl 卡到 timeout,等永远不会来的 body 字节

正确写法就是 curl -I —— 同样效果,不会卡。

-D 把响应头单独存文件

想把 body 管道给另一个命令、又想把响应头存成文件:

Bash
# 响应头存到 headers.txt, body 管道给 jq
curl -s -D headers.txt https://api.github.com/repos/torvalds/linux | jq .name

# 之后再看存下来的响应头
cat headers.txt

-D(或 --dump-header)把响应头写到文件,body 单独输出到 stdout。适合事后需要看 ETagX-RateLimit-Remaining 的 API 工作流。

跟随重定向

服务器返回 301302 时,curl 默认不跟随重定向。你只看到第一个响应:

Bash
$ curl -I https://github.com/torvalds
HTTP/1.1 301 Moved Permanently
Location: https://github.com/torvalds/linux

-L 跟随:

Bash
$ curl -IL https://github.com/torvalds
HTTP/1.1 301 Moved Permanently
Location: https://github.com/torvalds/linux

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
...

你会看到每一跳的响应头。配合 -o /dev/null 抑制 body、只留最终状态码:

Bash
# 重定向之后最终的 HTTP 状态码
curl -IL -o /dev/null -w \"%{http_code}n\" https://github.com/torvalds
# 200

常见坑

有些服务器不实现 HEAD

少数服务器会忽略 HEAD 请求或返回 405 Method Not Allowed。这种时候:

Bash
# -I 失败就回退 -i + 抑制 body
curl -I https://example.com || curl -is https://example.com | head -10

(-s 关掉进度条;用 head -10 把 body 截掉。)

CDN 对 HEAD 和 GET 可能返回不同内容

Cloudflare、Fastly、CloudFront 有时把 HEAD 响应和 GET 响应分开缓存。如果 -I 看到 X-Cache: MISS-iX-Cache: HIT,说明缓存把它们当作不同的缓存 key。

-i + -o 仍然把响应头打到 stdout

如果用 -o 把 body 存到文件,响应头还是去 stdout(不去文件)。想分开存,就用 -D headers.txt 存到文件,再 --silent 关掉 stdout:

Bash
# body 存文件,响应头存另一个文件,stdout 没噪音
curl -s -D headers.txt -o body.html https://example.com

-I-X POST 互斥

不小心写一起 curl 直接报错:

Bash
$ curl -X POST -I https://example.com
curl: (3) HTTP: flags used together are mutually exclusive

-I 强制用 HEAD,所以你没法再覆盖。

更深一层:--trace--trace-ascii

要超过 -v 给的信息,用 --trace--trace-ascii。它们把每一个字节(进出都算,包括 TLS 加密流)都 dump 到文件:

Bash
curl --trace-ascii trace.txt https://example.com
# 之后看 trace.txt —— 完整请求、完整响应、所有计时

只想 trace 特定组件(只要 TLS,只要网络),用 --trace-config:

Bash
# 只 trace TLS 握手
curl -v --trace-config tls https://example.com 2>&1 | head -30

速查卡

任务 命令
只要响应头 curl -I https://example.com
响应头 + body(都 stdout) curl -i https://example.com
响应头存文件 curl -D headers.txt https://example.com
body 存文件,响应头 stdout curl -i -o body.html https://example.com
跟随所有重定向,显示所有响应头 curl -IL https://example.com
重定向后的最终状态码 curl -L -o /dev/null -w \"%{http_code}n\" https://example.com
完整请求/响应调试 curl -v https://example.com 2>&1
只 TLS 调试 curl -v --trace-config tls https://example.com
API 调用并查 rate limit curl -s -D - https://api.example.com/data
文件大小 + 最后修改时间 curl -I https://example.com/file

来源

最后修改: 2026年7月17日

作者

评论

发表评论

您的邮箱地址不会被公开。