curl 调试 HTTP 接口的 15 个场景:从 GET 到 --resolve 全流程

curl 调试 HTTP 接口的 15 个场景:从 GET 到 --resolve 全流程

curlHTTP调试LinuxUbuntu
📶 入门 🧩 curl · Ubuntu

调试一个 HTTP 接口时,浏览器开发者工具、Postman 之类的图形工具都要先绕一层——装客户端、登录、配代理。curl 不用。它是 Ubuntu 24.04 自带的命令行 HTTP 客户端,装完系统第一分钟就能用,SSH 连上一台陌生服务器,它往往是你唯一可用的调试工具。

Ubuntu 24.04 仓库里的 curl 是 8.5.0(安全补丁版 8.5.0-2ubuntu10.8,apt-cache policy curl 可查),下文所有命令和参数都在这个版本验证过。低版本如 7.81(Ubuntu 22.04)的参数绝大多数也适用,个别如 --retry-all-errors 需要 curl 7.71+,遇到参数不认识先 curl --version 看一眼。

环境差异是最常见的翻车点,不是参数记错。 服务器上 curl 版本老、本地版本新,同一个命令行为不同,先确认两边版本再排查。

先建立坐标系:URL 与请求方法

curl 的第一个参数就是 URL,方法、头、体都靠选项附加。最基本的一条命令只有 URL:

curl https://httpbin.org/get

默认方法是 GET,响应体直接打到终端。选项的记法有规律:单字母短选项(-o、-d、-I)是高频操作,长选项(—resolve、—connect-timeout)是低频但功能重的操作。 两套可以混用,curl -d '{}' https://example.com/api 和 curl --data '{}' https://example.com/api 完全等价。

调试时先记住两件事:方法用 -X 显式指定(如 -X POST),头用 -H 追加(可重复多次)。这两个选项贯穿后面所有场景。

场景 1-5:请求体怎么发

场景 1:GET,只想快速看一眼响应体。 最简形式,URL 直接跟:

curl https://httpbin.org/get

场景 2:POST 表单。 表单字段用 -d,curl 自动加 Content-Type: application/x-www-form-urlencoded:

curl -d "username=admin&password=secret" https://httpbin.org/post

场景 3:POST JSON。 显式声明 Content-Type,body 用单引号包住,shell 不会拆词:

curl -X POST -H "Content-Type: application/json" \
  -d '{"name":"nginx","version":"1.24"}' \
  https://httpbin.org/post

# 从文件读 body:
curl -d @payload.json https://httpbin.org/post

-d @文件名 是调大请求体时的标准做法,命令行放不下长 JSON。单引号包 JSON 是 curl 调试的第一条纪律——用双引号,shell 会把 $ 和 ` 都展开,body 就变了样。

场景 4:PUT / DELETE / PATCH。 方法换了,结构不变:

curl -X PUT -d '{"status":"on"}' https://httpbin.org/put
curl -X DELETE https://httpbin.org/delete

场景 5:只想看响应头,不要 body。 -I(大写 i)发 HEAD 请求,只返回头:

curl -I https://example.com

适合快速确认状态码、缓存头、重定向目标。注意 -I 发的是 HEAD 请求——有些接口对 HEAD 返回和 GET 不同的状态码,要看 GET 的真实响应头用 -s -o /dev/null -D -,这个组合在场景 10 展开。

场景 6-10:响应怎么读

场景 6:跟随重定向。 默认 curl 停在 301/302 就返回,加 -L 跟到底:

curl -L https://example.com/old-path

场景 7:把响应存文件而不是终端。 -o 指定文件名,-O 用远端文件名保存:

# 下载大文件别忘 -L:
curl -LO https://example.com/install.sh

-o 搭配 -s(静默进度)和 -w(输出统计)是脚本里最常用的组合,见场景 14。

场景 8:带认证调用接口。 Basic 认证用 -u,Bearer token 放在头里:

curl -u admin:secret https://httpbin.org/basic-auth/admin/secret
curl -H "Authorization: Bearer eyJhbG..." https://httpbin.org/bearer

场景 9:带 cookie。 响应里的 Set-Cookie 存下来,后续请求带上:

curl -c cookies.txt https://httpbin.org/get          # 存
curl -b cookies.txt https://httpbin.org/get          # 带

场景 10:把状态码、耗时等指标打到 stdout。 -w 后跟格式串,curl 把内部变量替换成实际值:

curl -s -o /dev/null -w '%{http_code} %{time_total}\n' https://example.com

这行命令在脚本里做接口健康检查最常见:状态码加总耗时一行出。-w 是 curl 从调试工具变成监控工具的关键。 常用变量见下表。

变量含义
%{http_code}最后一个响应的状态码
%{time_namelookup}DNS 解析耗时
%{time_connect}TCP 握手耗时
%{time_appconnect}TLS 握手耗时(HTTP)
%{time_starttransfer}从发请求到收到首字节(TTFB)
%{time_total}总耗时
%{size_download}下载字节数

场景 11-15:网络层怎么管

场景 11:看完整请求和响应。 -v 打印整个会话,> 开头是发出去的请求行,< 开头是收到的响应行,* 开头是连接信息:

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

要写进工单或日志,用 --trace-ascii 文件名,比 -v 更完整。

场景 12:强制覆盖 DNS 解析。 域名还没生效、想提前验证新机器时,--resolve 让 curl 把指定域名解析到指定 IP,不发真实 DNS 查询:

curl --resolve api.example.com:443:203.0.113.10 https://api.example.com/health

证书校验仍按原域名进行,证书不匹配照样报错——这正是这个场景的价值:测的是新机器对原域名的真实表现,连证书都对齐了。 灰度切流前用它验证新机器,比改 hosts 文件干净。

场景 13:走代理。 -x 指定代理,协议写在代理地址前:

curl -x http://proxy.internal:8080 https://example.com
curl -x socks5h://127.0.0.1:1080 https://example.com

socks5h 的 h 表示域名也走代理解析,服务器本身解析不了的域名用它。

场景 14:限时与重试。 脚本里调接口必须设超时和重试,否则一个卡住的请求能挂住整个 cron:

curl --connect-timeout 5 -m 30 --retry 3 --retry-delay 2 \
  --retry-all-errors -f -s -o /dev/null https://example.com/health
参数含义
--connect-timeout 5TCP 连接阶段最多等 5 秒
-m 30整个请求(含传输)最多 30 秒
--retry 3失败重试 3 次(默认只重试瞬时错误)
--retry-all-errors任何错误都重试(需 curl 7.71+)
-fHTTP 状态码 ≥ 400 时返回非零退出码
-s隐藏进度条和错误信息

-f 是脚本场景的关键参数:没有它,curl 收到 500 也会正常退出 0,脚本把失败当成功。

场景 15:压测前先单发,模拟真实客户端。 -A 改 User-Agent,-e 改 Referer,--compressed 声明支持压缩:

curl -A "Mozilla/5.0" -e "https://example.com/page" --compressed \
  https://httpbin.org/get

这些头影响服务端缓存和 CDN 行为,测试环境模拟线上客户端时靠它们对齐。

一个可直接贴进 crontab 的健康检查

把场景 10 和 14 组合,就是一个最小可用的接口巡检脚本:

#!/usr/bin/env bash
set -euo pipefail
URL="https://example.com/health"
code=$(curl -s -o /dev/null -w '%{http_code}' \
  --connect-timeout 5 -m 30 --retry 2 --retry-delay 2 \
  --retry-all-errors -f "$URL")
echo "$(date '+%F %T') $URL $code"

-f 保证 5xx 会触发重试,重试耗尽退出非零,set -e 接住非零退出,cron 的邮件通知能收到。这十几行替代了大部分「接口挂了才发现」的场景。

场景速查表

需求命令
GETcurl URL
POST JSONcurl -X POST -H "Content-Type: application/json" -d @body.json URL
只看响应头curl -I URL
跟随重定向curl -L URL
状态码+耗时curl -s -o /dev/null -w '%{http_code} %{time_total}\n' URL
完整调试curl -v URL
覆盖 DNScurl --resolve host:443:IP URL
代理curl -x socks5h://127.0.0.1:1080 URL
限时重试curl -f -s -o /dev/null --connect-timeout 5 -m 30 --retry 3 URL

常见问题

Q:curl -d 发 JSON,服务端收到的是乱码或字段缺失? 检查引号。双引号会让 shell 展开 $ 和反引号,JSON 内容被篡改。body 一律用单引号包,或用 -d @file.json 从文件读。

Q:脚本里 curl 返回 0,但接口明明返回了 500? curl 默认把 HTTP 错误状态码当「成功送达」处理,退出码 0。加 -f,状态码 ≥ 400 时退出码非零,脚本判断才准。

Q:-v 的输出里 >、<、* 分别是什么? > 开头是 curl 发出的请求行和头,< 是服务端返回的响应行和头,* 是 TLS、连接层信息。排查「请求到底发出去了什么」看 > 行。

Q:域名还没切 DNS,想先测新服务器? --resolve 域名:443:IP 让 curl 直连指定 IP,Host 头和 TLS SNI 仍是原域名,证书校验照常进行。比改系统 hosts 干净,不用 root 权限。

Q:HTTPS 报证书错误,-k 关掉校验行不行? -k(--insecure)跳过证书校验,调试自签名证书的测试环境可以临时用,生产排查别养成习惯。要看具体证书内容用 -v 输出里的 TLS 段。

命令速记

15 个场景收敛下来,日常高频的就这几件事:-d 发体、-I 看头、-L 跟重定向、-v 看全程、-w 出指标、--resolve 盖 DNS、超时重试加 -f。把这七个动作记住,九成接口调试不需要打开图形工具。

服务器上的 curl 版本一般落后本地一两年,行为差异集中在新增参数上。遇到「本地能跑服务器不能跑」,先 curl --version,再查参数是不是新版本引入的。