1. curl 基础与常见参数
一句话总结: curl 是「命令行 HTTP 客户端」,
-s静默、-i带响应头、-o落盘、-L跟随跳转、-v看全过程,五个参数覆盖八成的日常请求。
# 基本请求输出到 stdout
curl https://api.example.com/health
# 静默(无进度条)+ 响应体
curl -s https://api.example.com/health
# 带响应头查看
curl -si https://api.example.com/health
# 落盘保存
curl -so health.json https://api.example.com/health
# 跟随 301/302 跳转
curl -sL http://example.com
1.1 查看请求细节
# -v 打印握手、请求头、响应头全过程
curl -sv https://api.example.com/health
# 只打印响应头
curl -sI https://api.example.com/health
# 限时防止挂死
curl -s --max-time 10 https://api.example.com/health
一句话总结: 排查问题先
-v看全貌、-I只看头、--max-time设超时,诊断脚本里这三样必备。
1.2 输出与静默的组合
# 丢弃响应体,只保留退出码用于判断
curl -so /dev/null -w '%{http_code}\n' https://api.example.com/health
# 输出统计信息
curl -s -o /dev/null -w '连接:%{time_connect} 首字节:%{time_starttransfer} 总:%{time_total}\n' \
https://api.example.com/health
2. HTTP 请求方法与会话
一句话总结:
-X指定方法、-H加请求头、-d发表单、-F发 multipart、-b/-c管理 Cookie,curl 把浏览器做的事全部搬进脚本。
# GET 带查询参数
curl -sG --data-urlencode "q=shell 脚本" https://api.example.com/search
# POST JSON
curl -s -X POST -H 'Content-Type: application/json' \
-d '{"name":"demo","size":10}' https://api.example.com/items
# PUT 更新
curl -s -X PUT -d '{"size":20}' https://api.example.com/items/1
2.1 表单与文件上传
# 普通表单(application/x-www-form-urlencoded)
curl -s -d 'user=alice&pass=secret' https://api.example.com/login
# multipart 文件上传
curl -s -F 'file=@/tmp/report.pdf' -F 'note=月度报表' \
https://api.example.com/upload
# 自定义请求头
curl -s -H 'Accept: application/json' -H "Authorization: Bearer $TOKEN" \
https://api.example.com/me
一句话总结: JSON 用
-H 'Content-Type: application/json'+-d,文件用-F,鉴权头用-H "Authorization: Bearer ..."——三类写法规整,脚本可读性就好。
2.2 Cookie 会话
# 登录拿 Cookie,后续请求复用
curl -s -c cookies.txt -d 'user=alice&pass=secret' https://api.example.com/login
curl -s -b cookies.txt https://api.example.com/profile
# 指定来源与 UA(防部分接口反爬校验)
curl -s -A 'Mozilla/5.0' -e 'https://example.com/' https://api.example.com/items
3. 下载与上传
一句话总结:
-O按远端文件名保存、-o自定义文件名、-C -断点续传、--limit-rate限速,批量下载与镜像同步都靠它们。
# 按远端文件名保存
curl -sO https://example.com/file.zip
# 自定义文件名
curl -so app.tgz https://example.com/downloads/app-1.2.3.tgz
# 断点续传
curl -sC - -o app.tgz https://example.com/downloads/app-1.2.3.tgz
# 限速 512KB/s
curl -s --limit-rate 512k -o app.tgz https://example.com/app.tgz
3.1 多文件与镜像下载
# 批量下载(配合 xargs/parallel)
cat urls.txt | xargs -P 4 -I {} curl -sO '{}'
# 目录结构保持(wget 更擅长)
wget -r -np -nH https://example.com/docs/
# 校验下载完整性
curl -so pkg.tar.gz https://example.com/pkg.tar.gz
echo "$EXPECTED_SHA256 pkg.tar.gz" | sha256sum -c -
一句话总结: 单文件下载用 curl,递归镜像用 wget;下载后
sha256sum -c校验,自动化里不能跳过完整性检查。
3.2 大文件与进度
# 显示进度条(非静默)
curl -# -O https://example.com/big.iso
# 断点续传 + 重试组合
curl -sC - --retry 5 --retry-delay 3 -o big.iso https://example.com/big.iso
4. 代理与认证
一句话总结:
-x指定 HTTP/SOCKS 代理、-U代理认证、-u基础认证、--cacert/-k控制 TLS 校验,内网与抓包场景都靠它们打通。
# HTTP 代理
curl -s -x http://proxy.example.com:3128 https://api.example.com/health
# SOCKS5 代理
curl -s --socks5-hostname 127.0.0.1:1080 https://api.example.com/health
# 基础认证
curl -su 'user:pass' https://api.example.com/private
4.1 代理环境变量
# 全局代理环境变量
export https_proxy=http://proxy.example.com:3128
curl -s https://api.example.com/health # 自动走代理
# 某次请求绕过代理
curl -s --noproxy '*' https://internal.example.com/health
一句话总结:
https_proxy/http_proxy环境变量被 curl 默认读取,脚本里按需 export 或--noproxy '*'绕过。
4.2 TLS 校验与 CA
# 信任自签名证书(测试环境)
curl -sk https://self-signed.example.com/health
# 使用自定义 CA 文件
curl -s --cacert /etc/ssl/certs/custom-ca.pem https://internal.example.com/health
# 指定客户端证书(mTLS)
curl -s --cert client.crt --key client.key https://api.example.com/secure
5. 重试与容错
一句话总结:
--retry重试次数、--retry-delay间隔、--retry-all-errors连 4xx 也重试、--max-time单次超时,组合出健壮的请求模板。
# 网络错误重试 5 次,间隔 3 秒
curl -s --retry 5 --retry-delay 3 https://api.example.com/health
# 连接超时与总超时
curl -s --connect-timeout 5 --max-time 20 https://api.example.com/health
# 所有错误都重试(默认只重试瞬时错误)
curl -s --retry 5 --retry-all-errors https://api.example.com/health
5.1 状态码判断与自动重试
#!/usr/bin/env bash
set -euo pipefail
url="https://api.example.com/health"
for i in {1..5}; do
code=$(curl -so /dev/null -w '%{http_code}' --max-time 10 "$url" || echo 000)
if [[ "$code" == 200 ]]; then
echo "健康检查通过"
exit 0
fi
echo "尝试 $i/5 状态 $code"
sleep 3
done
echo "健康检查失败" >&2
exit 1
一句话总结: curl 的网络错误(连接失败)会返回非零退出码,但 5xx 是「成功请求 + 非 200 状态码」——脚本要分别处理:重试前者,重试后者要看幂等性。
5.2 幂等与安全重试
# GET 可安全重试;POST 需业务幂等才重试
# 只读接口放心 --retry,写操作自行判断
curl -s --retry 3 https://api.example.com/health
# 把 curl 退出码做精细处理
curl -s -o /dev/null https://api.example.com/health
case $? in
0) echo OK ;;
6) echo "无法解析主机" ;;
7) echo "连接被拒" ;;
28) echo "超时" ;;
*) echo "其他错误" ;;
esac
6. HTTP 状态诊断
一句话总结: 状态码 2xx 成功、3xx 跳转、4xx 客户端错、5xx 服务端错;
-w '%{http_code}'取码,-w还能取重定向链与大小等指标。
# 只看状态码
curl -so /dev/null -w '%{http_code}\n' https://api.example.com/health
# 查看重定向链
curl -sI -L https://example.com/old-path
# 或
curl -s -o /dev/null -w '%{url_effective}\n' -L https://example.com/old-path
6.1 常见状态码速查
| 状态码 | 含义 | 常见原因 |
|---|---|---|
| 200 | 成功 | 正常响应 |
| 301/302 | 永久/临时跳转 | 路径变更、HTTP→HTTPS |
| 401 | 未认证 | 缺 Token、认证失败 |
| 403 | 禁止访问 | 权限不足、被 WAF 拦截 |
| 404 | 不存在 | 路径拼错 |
| 429 | 请求过多 | 触发限流 |
| 500/502/503 | 服务端错误 | 应用崩溃、网关超时、过载 |
# 诊断 301 落到哪
curl -sIL https://example.com/old-path | grep -i '^HTTP/\|^Location:'
# 429 限流看响应头
curl -sI https://api.example.com/items | grep -i 'ratelimit'
一句话总结: 定位思路:4xx 先查请求本身(URL/头/权限),5xx 查服务端;301 用
-I -L追链,429 看Retry-After头再退避重试。
6.2 响应体与错误区分
# JSON 接口错误看响应体
curl -s https://api.example.com/items | jq '.error // .message'
# 同时输出状态码与响应体
resp=$(curl -s -w '\n%{http_code}' https://api.example.com/items)
body=${resp%$'\n'*}; code=${resp##*$'\n'}
echo "code=$code body=$body"
7. DNS 与连通性排查
一句话总结: 排查顺序「DNS 解析 → TCP 连通 → TLS 握手 → HTTP 状态」四步走;
dig/nslookup查 DNS,ping看基本连通,nc探端口。
# DNS 解析
dig +short api.example.com
nslookup api.example.com
# 基本连通性
ping -c 3 api.example.com
# 端口连通性
nc -zv api.example.com 443
# 全链路:curl 分阶段计时
curl -sv https://api.example.com/health 2>&1 | grep -E 'Connected|TLS|HTTP/'
7.1 分层定位
| 现象 | 第一步查 | 命令 |
|---|---|---|
| 解析失败 | DNS | dig +short、nslookup |
| 不通 | 路由/防火墙 | ping、traceroute |
| 端口不通 | 防火墙/服务未起 | nc -zv host port |
| 连接建立但 TLS 失败 | 证书/版本 | openssl s_client -connect host:443 |
| HTTP 异常 | 状态码/头 | curl -sI、-w '%{http_code}' |
# TLS 层诊断
openssl s_client -connect api.example.com:443 -servername api.example.com \
< /dev/null 2>&1 | grep -E 'subject|issuer|Verify'
# 端口探活
for port in 80 443 3306; do
nc -zvw 3 api.example.com "$port" 2>&1
done
一句话总结: 「域名解析不出 → 网络不通 → 端口没开 → TLS 证书错 → HTTP 状态非 2xx」是按层排除的固定套路,命令从上往下逐个试。
7.2 脚本化健康检查
#!/usr/bin/env bash
set -euo pipefail
check_host() {
local url="$1"
local code
code=$(curl -so /dev/null -w '%{http_code}' --max-time 10 "$url" || echo 000)
echo "$url -> $code"
[[ "$code" =~ ^2[0-9][0-9]$ ]]
}
for u in https://web.example.com/health https://api.example.com/health; do
check_host "$u" || echo "!! $u 异常"
done
8. 总结
| 环节 | 要点 |
|---|---|
| 基础参数 | -s 静默、-i/-I 响应头、-o 落盘、-L 跟随、--max-time 超时 |
| 方法与会话 | -X 方法、-H 头、-d/-F 表单、-b/-c Cookie |
| 下载上传 | -O/-o 保存、-C - 续传、--limit-rate 限速、sha256 校验 |
| 代理认证 | -x 代理、--socks5、-u 认证、--cacert/-k TLS |
| 重试容错 | --retry + --retry-delay + --retry-all-errors,退出码 6/7/28 语义 |
| 状态诊断 | 2xx/3xx/4xx/5xx 分类,-w '%{http_code}' 取码,429 看 Retry-After |
| DNS/连通 | dig/nslookup/ping/nc/openssl 按层排除 |
| 脚本化 | -w '%{http_code}' 做健康检查,退出码 case 分支处理 |
curl 让脚本从「本地执行」跨入「与外部服务交互」:请求模板化、超时重试化、状态码判分化。诊断网络问题坚持「DNS → 连通 → TLS → HTTP」的分层套路。下一步是性能优化,把脚本从「能跑」推向「跑得快」。
延伸阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。