curl —— 命令行 HTTP 客户端
curl —— 命令行 HTTP 客户端
分类:03 文件与传输 适用:全平台(libcurl),几乎所有发行版预装 一句话:验证接口、排查 HTTP 问题、下载上传,一条命令搞定。
1. 它解决什么问题
- 接口返回 502/403,到底是网关、证书还是应用的问题?
- 需要带自定义 header、Cookie、证书、代理访问。
- 上传文件、调 REST API、看完整请求响应过程。
- 精确测出 DNS、连接、TLS、首字节各阶段耗时。
2. 基础用法
curl https://example.com # 输出到 stdout
curl -o page.html https://example.com # 存文件
curl -O https://example.com/file.tar.gz # 用远端文件名
curl -s https://api.example.com/data # 静默(不显示进度)
curl -sS https://api.example.com/data # 静默但显示错误(常用)
curl -L https://example.com # 跟随重定向
curl -I https://example.com # 只看响应头(HEAD)
curl -i https://example.com # 响应头 + body
curl -v https://example.com # 完整过程(含握手)
3. 请求构造
# GET 带参数(注意引号,避免 & 被 shell 解释)
curl -s 'https://api.example.com/search?q=redis&page=2'
# POST JSON
curl -s -X POST https://api.example.com/users \
-H 'Content-Type: application/json' \
-d '{"name":"tom","age":18}'
# 表单
curl -s -X POST https://api.example.com/login -d 'user=tom&pass=123'
# URL 编码(避免手写 %20)
curl -s -G https://api.example.com/search --data-urlencode 'q=redis 集群'
# 上传文件(multipart)
curl -s -F 'file=@/tmp/app.log' -F 'type=log' https://api.example.com/upload
# PUT 上传
curl -s -T /tmp/big.bin https://api.example.com/upload/big.bin
# 自定义方法 + 无 body
curl -s -X DELETE https://api.example.com/users/1
curl -s -X OPTIONS -i https://api.example.com/users
# 常用头
curl -s -H 'Authorization: Bearer <token>' \
-H 'Accept: application/json' \
-H 'X-Request-Id: 12345' \
https://api.example.com/me
4. 认证与证书
curl -u user:pass https://example.com # Basic Auth
curl --digest -u user:pass https://example.com # Digest
curl -k https://self-signed.example.com # 跳过证书校验(仅测试)
curl --cacert /etc/ssl/ca.crt https://internal.example.com # 指定 CA
curl --cert client.crt --key client.key https://mtls.example.com # 双向 TLS
curl --cert-type P12 --cert client.p12:password https://mtls.example.com
5. 连接与超时
curl --connect-timeout 5 --max-time 30 https://example.com
curl --retry 3 --retry-delay 2 --retry-connrefused https://example.com
curl --limit-rate 1m -O https://example.com/big.iso # 限速
curl -C - -O https://example.com/big.iso # 断点续传
curl --resolve api.example.com:443:10.0.0.5 https://api.example.com # 绕过 DNS 指定 IP
curl -x http://proxy:8080 https://example.com # 走代理
curl -x socks5h://127.0.0.1:1080 https://example.com
curl --http1.1 https://example.com # 强制 HTTP/1.1
curl --http2 https://example.com
curl -4 / -6 https://example.com # 强制 IPv4/IPv6
--resolve 是排查"DNS 解析到旧 IP"最有用的参数:不改 hosts 就能验证新机器。
6. 输出控制(排障关键)
# 只取状态码
curl -s -o /dev/null -w '%{http_code}\n' https://example.com
# 分阶段耗时
curl -s -o /dev/null -w '
dns: %{time_namelookup}
connect: %{time_connect}
tls: %{time_appconnect}
ttfb: %{time_starttransfer}
total: %{time_total}
code: %{http_code}
size: %{size_download}
ip: %{remote_ip}
' https://example.com
| 变量 | 含义 | 异常指向 |
|---|---|---|
time_namelookup |
DNS 解析耗时 | 大 → DNS 问题 |
time_connect |
TCP 握手完成 | 与 namelookup 差值大 → 网络 RTT/防火墙 |
time_appconnect |
TLS 握手完成 | 大 → 证书链、TLS 版本、OCSP |
time_starttransfer |
首字节 | 大 → 服务端处理慢 |
time_total |
总耗时 | |
remote_ip |
实际连接 IP | 确认是否走了预期节点 |
size_download |
下载字节 |
一键健康检查脚本:
curl -s -o /dev/null -w '%{http_code} %{time_total}s %{remote_ip}\n' "$1"
7. 实战场景
7.1 判断 502 是谁返回的
curl -sI https://api.example.com/health
# Server: nginx → 网关自己返的,上游挂了
# Server: nginx/1.24.0 + X-Powered-By → 应用返回
curl -sv https://api.example.com/health 2>&1 | head -40
看 Server、X-Powered-By、Via、X-Cache 等头判断链路。
7.2 验证证书与 TLS
curl -vI https://example.com 2>&1 | grep -E 'SSL|TLS|subject|expire|issuer'
curl -s --cert-status https://example.com # 检查 OCSP stapling
curl -sI --tlsv1.2 https://example.com # 强制某版本
7.3 带 Cookie 的会话调试
curl -c /tmp/cookie.txt -d 'user=tom&pass=123' https://example.com/login
curl -b /tmp/cookie.txt https://example.com/profile
7.4 下载并校验
curl -fL -o app.tar.gz https://example.com/app.tar.gz || echo "下载失败"
sha256sum app.tar.gz
-f(--fail)让 HTTP 4xx/5xx 返回非 0 退出码,否则 curl 会把错误页当成功保存。
7.5 压测前的连通性基线
for i in $(seq 1 10); do
curl -s -o /dev/null -w '%{http_code} %{time_total}\n' https://api.example.com/ping
done
先确认单请求正常,再上 ab/wrk,否则压测结果没有意义。
7.6 上传到对象存储(预签名 URL)
curl -s -X PUT -T backup.tar.gz \
-H 'Content-Type: application/octet-stream' \
'https://bucket.oss-cn-hangzhou.aliyuncs.com/backup.tar.gz?Signature=...'
8. 常见坑
-d默认就是 POST,再写-X POST冗余;但-X GET -d会发送带 body 的 GET,很多服务端直接拒绝。-L与-X冲突:重定向后 curl 仍用指定方法,301 后本该 GET 却继续 POST,导致 405。用--post301 --post302显式控制。-I发的是 HEAD:有些服务不支持 HEAD 返回 405,用-s -D - -o /dev/null取头。-k会掩盖真实证书问题:生产排障先不加-k,看清楚错在哪。- URL 里的
&必须引号包住,否则 shell 后台执行,命令被截断。 -o与-O混用:-O用远端名,配--output-dir更好。- 不加
-f下载失败也返回 0:脚本里必须-f。 - 大文件默认全在内存:用
-o落盘,不要管道给变量。 - HTTP/2 下 header 名被小写,抓包/日志比对时注意。
- 代理环境变量会干扰:
http_proxy/https_proxy/no_proxy影响 curl,排查时用--noproxy '*'。 --resolve只影响 DNS,SNI 仍是 URL 里的域名,这正是它的价值。-w里的换行:在-w字符串中用真实换行或\n,注意 shell 引号类型。
9. 速查表
curl -sS <url> # 静默+报错
curl -sI <url> # 响应头
curl -sv <url> # 全过程
curl -L -o file <url> # 跟随重定向下载
curl -fL -O <url> # 失败即错误
curl -s -o /dev/null -w '%{http_code} %{time_total}\n' <url>
curl -X POST -H 'Content-Type: application/json' -d '{...}' <url>
curl -F 'file=@/path' <url> # 上传
curl -u user:pass <url> # Basic
curl --resolve host:443:1.2.3.4 https://host/ # 指定 IP
curl -x http://proxy:8080 <url> # 代理
curl -C - -O <url> # 断点续传
curl --connect-timeout 5 --max-time 30 <url>