返回博客
网络爬虫技术
Suciu DanLast updated on Apr 29, 20263 min read

cURL 中的 HTTP 响应头:每个标记、技巧和脚本配方

cURL 中的 HTTP 响应头:每个标记、技巧和脚本配方
简而言之:cURL 默认会隐藏响应头。使用 -i 可同时查看响应头和正文, -I 用于仅返回响应头的 HEAD 请求, -v 用于全面的请求/响应调试,以及 -D 将头部信息保存到文件中。对于现代脚本编写,cURL 7.83 及以上版本支持通过 -w write-out 选项将所有标头导出为 JSON。

简介

HTTP 响应头是服务器随每次响应返回的元数据,涵盖从内容类型和缓存策略到速率限制计数器和安全指令等所有内容。当您调试不稳定的 API、验证 CDN 是否提供正确的缓存头,或检查网站是否设置了正确的 CORS 策略时,大多数开发者首先会使用 cURL。

默认情况下,cURL 仅将响应正文输出到标准输出(stdout),这意味着您必须在 cURL 中显式请求 HTTP 响应头才能查看它们。挑战在于,cURL 提供了至少六种显示这些头的标志和技巧,且每种都针对不同的工作流程进行了优化。您应该选择 -i, -I, -v,还是 -D?至于较新的 -w 写出变量呢?这些功能既能按名称提取单个标头,也能将所有标头导出为 JSON。

本指南将带您逐一了解 cURL 中查看 HTTP 响应头的所有方法,从最简单的单行命令到适合自动化的脚本方案,让您无需死记硬背每段手册页内容,也能为具体任务选择合适的工具。

响应头在调试和爬网中的重要性

每个 HTTP 响应都携带一组标头,用于告知客户端如何解析有效载荷。一个 Content-Type 标明 application/json 表示一种含义; text/html 则表示另一层含义。除了基础功能外,头部信息还揭示了缓存行为(Cache-Control, ETag)、身份验证要求(WWW-Authenticate)、速率限制状态(X-RateLimit-Remaining)以及安全策略(Strict-Transport-Security, Content-Security-Policy).

对于网络爬虫从业者而言,响应头信息尤为关键。它们能告诉你服务器是否对响应进行了压缩,你的请求是否被重定向到一系列中间 URL,或者你是否即将触发速率限制。正因如此,学会在 cURL 中快速准确地检查 HTTP 响应头,是任何在命令行上处理 HTTP 的人必备的基础技能。

如何在 cURL 中查看 HTTP 响应头:快速参考表

在深入探讨示例之前,这里提供一张可供收藏的对比表。它将每个标志与其行为以及在 cURL 中显示 HTTP 响应头时最实用的场景进行了映射。

标志 / 技巧

作用

最适合

-i (--include)

同时打印响应头和正文

快速查看响应内容

-I (--head)

发送 HEAD 请求,仅打印头部信息

当不需要请求正文时快速检查请求头

-v (--verbose)

显示完整的请求和响应,包括 TLS 握手

对整个 HTTP 事务进行深度调试

-D <file>

将响应头信息保存到文件

将头部与正文分开记录

-s -o /dev/null -D -

GET请求,仅将头部信息打印到标准输出

当 HEAD 响应与 GET 响应不同时

-w '%header{name}'

按名称提取单个头部(cURL 7.83+)

对特定头部进行脚本化检查

-w '%{header_json}'

将所有标头以 JSON 格式输出(cURL 7.83+)

将标头通过管道传输至 jq 或其他 JSON 工具

选择与您的工作流程相匹配的行,然后阅读下方的相应部分以了解详细信息和示例。

在正文旁边显示响应头 (-i)

在 cURL 中查看 HTTP 响应头最简单的方法是使用 -i 标志(长形式: --include)。它会指示 cURL 在正文输出前插入完整的响应头集,并以空行分隔。

curl -i https://httpbin.org/get

输出以状态行 (HTTP/1.1 200 OK),随后每个标头独占一行,接着是一行空行,最后是响应正文。这是一个 GET 请求,而非 HEAD 请求,因此您获得的是服务器实际会提供给浏览器的真实响应。

当您希望通过单条终端命令快速查看响应头和正文时,请使用 -i ,可在单条终端命令中快速查看响应头和正文。其缺点是响应头和正文混合在同一数据流中,这会增加程序解析的难度。若需编写脚本,建议采用后续介绍的技术(如 -D-w)通常更合适。

仅获取响应头 (-I 和 --head)

当您仅需获取头部信息且完全不关心正文内容时,请使用 -I (或其等效的长格式 --head)。这两个标志都会发送一个 HTTP HEAD 请求,仅向服务器请求头部信息。

curl -I https://httpbin.org/get

输出仅包含状态行和头部信息。没有正文,没有多余的冗余信息。 --head 拼写方式虽然功能相同,但在 shell 脚本中更清晰易读,能让代码审查者一目了然您的意图。

需注意一点:HEAD响应并不总是与GET响应完全一致。某些服务器在处理HEAD请求时会返回不同的头部信息(或完全省略某些头部)。若您正在排查仅在真正的GET请求中出现的头部问题,此标志可能会误导您。

仅打印 GET 请求的头部

解决方法是使用 -s -o /dev/null -D - 技术,它会发送完整的 GET 请求,但丢弃请求主体,仅将响应头打印到标准输出(stdout):

curl -s -o /dev/null -D - https://httpbin.org/get

以下是各部分的功能说明: -s 禁用进度条, -o /dev/null 将请求主体发送到空处, -D - 将响应头写入标准输出(连字符表示“标准输出”而非文件名)。这样既能获取真实的 GET 响应头,又避免了请求主体的干扰,当您需要在 cURL 中获取准确的 HTTP 响应头,而 HEAD 方法不可靠时,这是一种必不可少的处理方式。

使用详细模式 (-v) 检查完整的请求和响应

详细模式是 HTTP 调试的“瑞士军刀”。 -v (或 --verbose) 标志会让 cURL 打印完整的交易过程:TLS 握手细节、请求头、响应头以及正文。

curl -v https://httpbin.org/get

在输出中,以 > 的行是客户端发送的请求头,以 < 的行是服务器返回的响应头,而以 * 的行则是 cURL 自身生成的信息提示(连接信息、TLS 协商等)。

为减少冗余信息,请结合使用 -v-s 结合使用以隐藏进度条。若要在脚本中仅捕获详细输出中的标头行,可重定向 stderr( -v 写入调试信息的位置)并进行过滤:

curl -vs https://httpbin.org/get 2>&1 | grep '^<'

这会将 stdout 和 stderr 合并传输,然后仅保留以 <开头的行,从而从 cURL 的详细输出中获取一份干净的响应头列表。这非常适合快速的一次性调试,但对于生产环境脚本,您可能更需要接下来介绍的结构化方法。

将响应头保存到文件 (-D)

-D -D 标志(即 --dump-header) 会将响应头写入文件而非标准输出。结合 -o 可将请求主体单独保存:

curl -D headers.txt -o body.html https://example.com

执行此操作后, headers.txt 文件将包含所有响应头,而 body.html 文件则包含页面内容。这非常适合日志记录场景,可将响应头和正文并排存档以便后续审查。

若需带时间戳的日志记录(在监控脚本中非常有用),请动态生成文件名:

curl -D "headers_$(date +%Y%m%d_%H%M%S).txt" -o /dev/null https://example.com

每次运行都会生成一个类似 headers_20240615_143022.txt,这样您就可以追踪 cURL 中 HTTP 响应头随时间的变化。将其与 cron 任务结合使用,您便拥有了一个无需任何第三方工具的轻量级响应头监控器。

使用 grep 和 awk 提取特定标头

有时您可能只关注某个特定标头,例如 Content-TypeX-RateLimit-Remaining。将 cURL 的输出通过标准 Unix 工具进行管道传输,可以快速实现这一目标。

使用不区分大小写的 grep 按名称提取单个标头:

curl -sI https://httpbin.org/get | grep -i "content-type"

若要仅提取数值(不包含标头名称),请添加 cutawk:

curl -sI https://httpbin.org/get | grep -i "content-type" | cut -d':' -f2- | xargs

cut 命令以冒号为分隔符并保留其后所有内容,而 xargs 则会去除前后空格。或者, awk 可以一气呵成:

curl -sI https://httpbin.org/get | awk -F': ' '/^[Cc]ontent-[Tt]ype/ {print $2}'

请注意部分名称匹配的情况。使用 grep 搜索 Content 时,也会匹配 Content-Length, Content-Encoding,以及任何以相同方式开头的字符串。请务必匹配完整的标头名称后跟冒号,以避免误报。

使用 -w 进行现代标头提取(cURL 7.83+)

从大约 7.83 版本(2022 年初发布)开始,cURL 引入了两个写出变量,简化了在 cURL 脚本中提取 HTTP 响应头的过程: %header{name} 用于单个标头,以及 %{header_json} 用于以 JSON 格式提取所有标头。

干净地提取一个标头,无需使用 grep:

curl -s -o /dev/null -w '%header{content-type}' https://httpbin.org/get

这仅输出 Content-Type 。无需解析、无需管道、无需正则表达式。

若要获取所有响应头作为 JSON 对象,请使用:

curl -s -o /dev/null -w '%{header_json}' https://httpbin.org/get

输出结果是有效的 JSON,这意味着您可以将其直接通过管道传入 jq 进行格式化或字段提取:

curl -s -o /dev/null -w '%{header_json}' https://httpbin.org/get | jq '.["content-type"]'

当出现重复的标头名称(例如多个 Set-Cookie 个头)时,cURL 会将其按首次出现的位置进行分组,并将所有值收集到一个 JSON 数组中,因此您永远不会丢失数据。

重要提示:这些输出变量需要 cURL 7.83 或更高版本。运行 curl --version 来检查您的版本。如果您使用的是旧版本, grep/awk 上一节的方法仍是您的最佳选择。

脚本编写与自动化方案

一旦您能够在 cURL 中提取 HTTP 响应头,下一步就是围绕它们构建可重复的工作流。以下是三种适用于大规模头信息审计的有效模式。

在多个 URL 上审核特定标头:

while IFS= read -r url; do
  val=$(curl -s -o /dev/null -w '%header{strict-transport-security}' "$url")
  echo "$url → $val"
done < urls.txt

输入一个 URL 文件,快速获取哪些 URL 设置了 Strict-Transport-Security 该标头的URL。

使用 diff 监控随时间推移的标头变化:

curl -sI https://example.com > /tmp/headers_prev.txt
# ... wait, or run via cron ...
curl -sI https://example.com > /tmp/headers_now.txt
diff /tmp/headers_prev.txt /tmp/headers_now.txt

将此操作封装为 cron 任务,并将 diff 输出发送至 Slack webhook 或电子邮件。这是检测意外配置变更的简便方法。

为频繁检查创建 shell 别名:

alias hcheck='curl -s -o /dev/null -D - -w "\n"'

现在只需输入 hcheck https://example.com 即可通过干净的 GET 请求快速获取任意 URL 的响应头信息。

常见头部问题的排查

即便是简单的标头检查也可能出错。以下是使用 cURL 处理 HTTP 响应标头时可能遇到的三种情况,以及相应的解决方法。

SSL 证书错误

如果 cURL 因证书问题而拒绝连接,您可以使用 -k (或 --insecure):

curl -kI https://self-signed.example.com

仅在开发或内部测试环境中使用此方法。在生产环境中,更好的解决方法是提供正确的 CA 证书包,使用 --cacert /path/to/ca-bundle.crt ,确保连接经过实际验证。

重定向链与缺失的头部信息

默认情况下,cURL 不跟随重定向。如果 URL 返回 301 或 302 状态码,您只能看到初始响应中的头部信息。添加 -L (或 --location) 来跟随重定向链:

curl -LI https://example.com

若要捕获每个跳转点的头部信息(而不仅是最终目标),请结合使用 -L-D:

curl -L -D all_headers.txt -o /dev/null https://example.com

该文件 all_headers.txt 将包含每次重定向的报头块,各块之间以空行分隔。您还可以设置 --max-redirs 5 来限制跳数,避免陷入无限循环。

字符编码与压缩

许多服务器会使用 gzip 或 Brotli 压缩响应,这可能会导致原始正文输出看起来像乱码。 --compressed 标志会指示 cURL 发送相应的 Accept-Encoding 标头并自动解压响应:

curl --compressed -i https://example.com

这不会改变头部信息本身,但可确保您能同时读取头部信息和正文。若仅需检查头部信息,压缩并非问题;但当您同时查看两者时,压缩就变得至关重要 -i 同时查看两者时,压缩就变得至关重要。

关键要点

  • 使用 -i 进行快速可视化检查,该工具会将响应头与正文并排显示;而 -I 仅需查看 HEAD 请求的头部信息时。
  • -s -o /dev/null -D - 模式在 HEAD 响应与 GET 响应不同时必不可少:它能提供真实的 GET 头部信息,且不含正文干扰。
  • 详细模式(-v) 是您工具库中最强大的工具,可一次性显示请求头、响应头和 TLS 详细信息。
  • cURL 7.83+ 输出变量 (%header{name}%{header_json}) 消除了对 grep/awk 管道的需求,并能与基于 JSON 的工作流无缝集成。
  • 结合 -L-D 以捕获每次重定向跳转的头部信息,并在依赖新功能前务必检查您的 cURL 版本。

常见问题

curl -i 和 curl -I 有什么区别?

curl -i 发送标准 GET 请求,并在输出中将响应头信息置于正文之上。 curl -I 发送 HEAD 请求,该请求仅返回头部,完全不包含正文。小写 -i 可获得完整的响应;大写 -I 速度更快,但在某些服务器上返回的头部可能与真正的 GET 请求不同。

如何将 cURL 响应头以 JSON 格式输出?

使用 -w '%{header_json}' write-out变量,该功能在cURL 7.83及更高版本中可用。运行 curl -s -o /dev/null -w '%{header_json}' <URL> 即可获取包含所有标头的有效 JSON 对象。将结果通过管道传入 jq 进行格式化或字段提取。重复的标头会自动归类到 JSON 数组中。

如何在 PowerShell 中使用 curl 查看响应头?

在 Windows 上, curl 在 PowerShell 中是 Invoke-WebRequest的别名。运行 (Invoke-WebRequest -Uri "https://example.com" -Method Head).Headers 可查看响应头部的哈希表。若需使用实际的 cURL 二进制文件,请调用 curl.exe -I https://example.com 以绕过别名,并使用本指南中描述的相同参数。

如何使用 cURL 查看重定向链中每个重定向的头部信息?

-L (跟随重定向)与 -D (dump headers) 如下所示: curl -L -D headers.txt -o /dev/null https://example.com。生成的文件将包含每个重定向节点的独立头部块,以空行分隔。您还可以使用 curl -Lv 在 stderr 上实时查看每个跳转点的头部信息。

结论

掌握在 cURL 中检查 HTTP 响应头的方法是一项实用技能,一旦掌握,每天都能派上用场。若需快速检查, -i-I 仅需一条命令即可完成。当您需要更深入的分析时, -v 可显示完整的交易过程, -D 并允许将头部信息写入文件以便后续分析。若您正在构建自动化管道,新版 -w 写出变量(cURL 7.83+ 版本可用)可让你直接提取格式整洁的 JSON 格式头部,无需任何繁琐的文本处理操作。

关键在于为任务匹配合适的标志。请将本指南中的快速参考表作为您的速查表,并基于脚本示例,将一次性命令转化为可重复执行的检查流程。

如果您的 cURL 脚本在尚未检查到头部信息前就已触发反机器人防护、验证码或 IP 封锁,WebScrapingAPI 可为您处理请求层,通过单一 API 端点管理代理轮换和封锁规避,让您专注于数据而非基础设施。

关于作者
Suciu Dan, 联合创始人 @ WebScrapingAPI
Suciu Dan联合创始人

Suciu Dan 是 WebScrapingAPI 的联合创始人,他撰写了关于 Python 网页抓取、Ruby 网页抓取以及代理基础设施的实用指南,这些指南专为开发者而设计。

开始构建

准备好扩展您的数据收集规模了吗?

加入2,000多家企业,使用WebScrapingAPI在无需任何基础设施开销的情况下,以企业级规模提取网络数据。