curl 深度教程 / 第 09 章:传输选项与网络调优
第 09 章:传输选项与网络调优
在生产环境中,网络状况千变万化。正确配置超时、重试和代理选项,是构建可靠网络应用的关键。
9.1 超时设置
超时参数对比
| 选项 | 说明 | 默认值 | 推荐值 |
|---|
--connect-timeout | TCP 连接建立超时 | 无限制 | 10-30 秒 |
-m / --max-time | 整个操作最大耗时 | 无限制 | 60-300 秒 |
--max-filesize | 最大下载文件大小 | 无限制 | 视场景而定 |
--speed-limit + --speed-time | 速率低于阈值时中止 | 无 | 视场景而定 |
基本超时配置
# 连接超时:10 秒内未建立连接则中止
curl --connect-timeout 10 https://slow-server.example.com
# 总超时:整个操作(含 DNS、连接、传输)最多 60 秒
curl --max-time 60 https://example.com/largefile.zip
# 组合使用
curl --connect-timeout 10 --max-time 300 \
https://example.com/largefile.zip
# 最大文件大小(超过则中止)
curl --max-filesize 104857600 https://example.com/download
# 限制为 100MB
速率感知超时
# 如果 30 秒内平均速度低于 1KB/s,则中止
curl --speed-limit 1024 --speed-time 30 \
-O https://example.com/slow-download.zip
# 用于检测服务器是否"卡住"
curl --speed-limit 100 --speed-time 60 \
--max-time 300 \
-O https://example.com/file.zip
超时场景参考
| 场景 | connect-timeout | max-time | 说明 |
|---|
| API 调用 | 5-10 秒 | 30 秒 | 快速失败 |
| 网页下载 | 10 秒 | 60 秒 | 允许加载时间 |
| 大文件下载 | 30 秒 | 3600+ 秒 | 按文件大小调整 |
| 健康检查 | 3 秒 | 5 秒 | 快速检测 |
| 批量请求 | 5 秒 | 30 秒 | 单个请求级超时 |
| 慢速服务器 | 30 秒 | 600 秒 | 容忍网络延迟 |
9.2 重试策略
基本重试
# 最多重试 3 次
curl --retry 3 -O https://example.com/unstable-server/file.zip
# 重试间隔 5 秒
curl --retry 3 --retry-delay 5 -O https://example.com/file.zip
# 使用指数退避(每次重试间隔翻倍)
curl --retry 3 --retry-delay 2 --retry-max-time 60 \
-O https://example.com/file.zip
# 第 1 次重试:2 秒后
# 第 2 次重试:4 秒后
# 第 3 次重试:8 秒后
# 设置重试的最大总时间
curl --retry 10 --retry-max-time 120 \
-O https://example.com/file.zip
# 重试总时间不超过 2 分钟
重试触发条件
curl 默认在以下 HTTP 状态码时重试:
| 状态码 | 含义 | 默认重试 |
|---|
| 408 | Request Timeout | ✅ |
| 429 | Too Many Requests | ✅ |
| 500 | Internal Server Error | ✅ |
| 502 | Bad Gateway | ✅ |
| 503 | Service Unavailable | ✅ |
| 504 | Gateway Timeout | ✅ |
# 自定义重试条件(curl 7.66+)
curl --retry 3 \
--retry-connrefused \
--retry-all-errors \
-O https://example.com/file.zip
# --retry-connrefused:连接被拒绝时也重试
# --retry-all-errors:所有错误都重试(包括 HTTP 错误)
生产级重试脚本
#!/bin/bash
# resilient_download.sh - 可靠的下载脚本
URL="$1"
OUTPUT="$2"
MAX_RETRIES=${3:-5}
RETRY_DELAY=${4:-5}
MAX_RETRY_TIME=${60:-300}
download() {
curl -sS -o "$OUTPUT" \
--connect-timeout 10 \
--max-time 600 \
--retry "$MAX_RETRIES" \
--retry-delay "$RETRY_DELAY" \
--retry-max-time "$MAX_RETRY_TIME" \
--retry-connrefused \
--retry-all-errors \
--speed-limit 10240 \
--speed-time 60 \
-C - \
"$URL"
}
if download; then
FILE_SIZE=$(stat -c%s "$OUTPUT" 2>/dev/null || echo 0)
echo "✅ 下载成功: $OUTPUT ($FILE_SIZE bytes)"
else
echo "❌ 下载失败: $URL"
rm -f "$OUTPUT"
exit 1
fi
9.3 代理配置
HTTP 代理
# 使用 HTTP 代理
curl -x http://proxy.example.com:8080 https://example.com
# 使用 HTTPS 代理
curl -x https://proxy.example.com:8443 https://example.com
# 需要认证的代理
curl -x http://proxy.example.com:8080 \
-U proxyuser:proxypass \
https://example.com
# 或在 URL 中包含认证信息
curl -x http://proxyuser:[email protected]:8080 \
https://example.com
# 使用环境变量设置代理
export http_proxy=http://proxy.example.com:8080
export https_proxy=http://proxy.example.com:8080
export no_proxy=localhost,127.0.0.1,.internal.example.com
curl https://external.example.com # 通过代理
curl https://internal.example.com # 不通过代理(匹配 no_proxy)
SOCKS 代理
# SOCKS4 代理
curl --socks4 127.0.0.1:1080 https://example.com
# SOCKS4a 代理(支持远程 DNS)
curl --socks4a 127.0.0.1:1080 https://example.com
# SOCKS5 代理
curl --socks5 127.0.0.1:1080 https://example.com
# SOCKS5 + 远程 DNS 解析(推荐)
curl --socks5-hostname 127.0.0.1:1080 https://example.com
# SOCKS5 代理认证
curl --socks5 127.0.0.1:1080 \
--proxy-user proxyuser:proxypass \
https://example.com
# 环境变量
export ALL_PROXY=socks5://127.0.0.1:1080
curl https://example.com
代理类型对比
| 类型 | 选项 | 特点 | 适用场景 |
|---|
| HTTP 代理 | -x http:// | 仅代理 HTTP 流量 | Web 访问 |
| HTTPS 代理 | -x https:// | TLS 隧道到代理 | 安全环境 |
| CONNECT 代理 | -p / --proxytunnel | 隧道模式 | HTTPS 流量 |
| SOCKS4 | --socks4 | TCP 代理,不支持远程 DNS | 旧应用 |
| SOCKS4a | --socks4a | 支持远程 DNS | 需要 DNS 隐私 |
| SOCKS5 | --socks5 | 支持 TCP/UDP | 通用代理 |
| SOCKS5h | --socks5-hostname | 远程 DNS 解析 | 推荐 |
代理排除规则
# 使用 --noproxy 排除特定主机
curl --noproxy "localhost,127.0.0.1,.internal.com" \
-x http://proxy.example.com:8080 \
https://api.internal.com/data
# 不使用代理
# 使用环境变量(更通用)
export no_proxy="localhost,127.0.0.1,.internal.example.com,10.0.0.0/8"
9.4 连接管理
连接池与 Keep-Alive
# curl 默认使用 HTTP/1.1 Keep-Alive
# 同一连接会自动复用
# 在同一连接上发送多个请求(使用 --next)
curl https://api.example.com/users \
--next https://api.example.com/orders \
--next https://api.example.com/products
# 强制关闭连接(禁用 Keep-Alive)
curl -H "Connection: close" https://api.example.com/data
DNS 缓存
# curl 默认不缓存 DNS(每次请求都解析)
# 使用 --resolve 手动指定 DNS 解析
curl --resolve example.com:443:93.184.216.34 https://example.com
# 使用 c-ares 进行异步 DNS(编译时启用 --enable-ares)
# 这样 curl 会缓存 DNS 结果
# 指定 DNS 服务器
curl --dns-servers 8.8.8.8,8.8.4.4 https://example.com
# 需要 c-ares 支持
# DNS 解析超时
curl --dns-timeout 10 https://example.com
IPv4/IPv6 控制
# 强制使用 IPv4
curl -4 https://example.com
# 强制使用 IPv6
curl -6 https://example.com
# 查看实际使用的 IP 版本
curl -v -4 https://example.com 2>&1 | grep "Connected"
# Connected to example.com (93.184.216.34) port 443
curl -v -6 https://example.com 2>&1 | grep "Connected"
# Connected to example.com (2606:2800:220:1:...) port 443
9.5 网络接口绑定
# 绑定到特定网络接口
curl --interface eth0 https://example.com
# 绑定到特定 IP 地址
curl --interface 192.168.1.100 https://example.com
# 指定本地端口范围
curl --local-port 5000-6000 https://example.com
# 多网卡环境下的出站控制
curl --interface 10.0.1.5 https://internal.example.com
curl --interface 192.168.1.5 https://external.example.com
9.6 TCP 参数调优
# 设置 TCP 连接的 keep-alive 间隔
curl --keepalive-time 60 https://example.com
# 禁用 TCP 缓冲(减少延迟,降低吞吐)
curl --tcp-nodelay https://example.com
# 设置最大连接数(配合 --next)
# 单个 curl 实例的连接数由请求数决定
# 使用 HTTP/1.0(禁用 keep-alive)
curl --http1.0 https://example.com
9.7 速率限制与带宽管理
# 限制上传速度
curl --limit-rate 1m -X PUT \
-F "[email protected]" \
https://upload.example.com
# 组合限速 + 断点续传
curl --limit-rate 2m -C - -O https://example.com/largefile.iso
# 限制请求速率(脚本中实现)
while read -r url; do
curl -sO "$url"
sleep 0.5 # 每个请求间隔 500ms
done < urls.txt
# 使用令牌桶算法(GNU parallel)
cat urls.txt | parallel -j 1 --delay 0.5 curl -sO {}
注意事项
- 代理环境变量优先级:
curl -x > https_proxy > http_proxy - SOCKS5h 推荐:使用
--socks5-hostname 避免 DNS 泄露 - 超时层级:
--connect-timeout < --max-time < --retry-max-time - 重试间隔:避免过于频繁的重试导致服务器过载(使用指数退避)
- 连接复用:同一目标的多个请求自动复用 TCP 连接
# 完整的网络诊断命令
curl -v --connect-timeout 5 --max-time 30 \
-4 --interface eth0 \
-x "" \ # 忽略代理环境变量
https://example.com 2>&1 | head -30
扩展阅读
📖 下一章:第 10 章:TLS/SSL 安全 — 深入了解 TLS 配置、证书验证、自签名证书和密码套件管理。