Linux curl 命令深度解析:从 HTTP 请求到网络调试实战

curl 的本质:libcurl 的命令行包装

摘要:curl 是 libcurl 库的命令行封装,支持 20+ 种网络协议。本文深入解析 curl 的底层实现(TCP 连接复用、DNS 解析缓存)、核心参数(-X、-H、-d、-o 等)的用法与陷阱,并涵盖 SSL 调试、Cookie 管理、并发请求、断点续传等高级技巧。通过实战脚本示例,帮助读者从"会用"进阶到"精通",真正掌握 HTTP 调试与网络性能分析的核心能力。

curl 的全称是 "Command Line URL",底层依赖 libcurl 库。libcurl 支持 20+ 种协议(HTTP/HTTPS/FTP/SMTP 等),而 curl 命令只是这个库的 CLI 接口。

这意味着你在命令行中调用的每个选项,最终都会映射到 libcurl 的 C API:

bash 复制代码
// curl_easy_setopt() 对应命令行选项
curl_easy_setopt(handle, CURLOPT_URL, "https://example.com");  // 对应 URL 参数
curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L);         // 对应 -L 参数
curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);                // 对应 -v 参数

了解这个映射关系,有助于理解 curl 的设计哲学:每个命令行选项都是 libcurl API 的直接暴露

HTTP 请求的底层实现

TCP 连接复用

curl 默认会复用 TCP 连接(HTTP Keep-Alive)。通过 --no-keepalive 可以禁用:

bash 复制代码
# 默认复用连接(Keep-Alive)
curl https://example.com/api/1
curl https://example.com/api/2  # 复用同一个 TCP 连接

# 禁用 Keep-Alive
curl --no-keepalive https://example.com

底层实现:curl 会在内存中维护一个连接池(connection cache),key 是 host:port。当发起请求时,先检查池中是否有可用连接,有则直接使用,没有才建立新连接。

DNS 解析缓存

curl 默认不缓存 DNS 解析结果,每次请求都会重新解析。可以通过 --resolve 手动指定 IP:

bash 复制代码
# 强制 curl 使用指定 IP(绕过 DNS 解析)
curl --resolve "example.com:443:192.168.1.100" https://example.com

# 调试 DNS 负载均衡时特别有用
curl --resolve "api.example.com:443:10.0.0.1" https://api.example.com/health
curl --resolve "api.example.com:443:10.0.0.2" https://api.example.com/health

这在调试 CDN、负载均衡时非常有用,可以直接指定后端服务器 IP。

核心参数深度解析

-X/--request:请求方法

bash 复制代码
# 常见的 GET/POST/PUT/DELETE
curl -X POST https://api.example.com/users

# 但有些方法有专用选项,不需要 -X
curl -d '{"name":"test"}' https://api.example.com/users  # 自动变成 POST
curl -I https://api.example.com/users                     # 自动变成 HEAD

陷阱-d 会自动设置 Content-Type: application/x-www-form-urlencoded,除非你手动覆盖:

bash 复制代码
# 发送 JSON 数据
curl -d '{"name":"test"}' \
     -H "Content-Type: application/json" \
     https://api.example.com/users

-H/--header:请求头控制

bash 复制代码
# 添加多个请求头
curl -H "Authorization: Bearer token123" \
     -H "X-Request-ID: $(uuidgen)" \
     https://api.example.com

# 删除默认请求头(curl 默认发送的)
curl -H "User-Agent:" https://api.example.com  # 删除 User-Agent
curl -H "Accept:" https://api.example.com      # 删除 Accept

User-Agent 的默认值curl/7.68.0,可以通过 -A-H "User-Agent: xxx" 修改。

-d/--data:请求体数据

-d 的数据编码方式取决于 Content-Type

bash 复制代码
# application/x-www-form-urlencoded(默认)
curl -d "name=张三&age=25" https://api.example.com
# 实际发送:name=%E5%BC%A0%E4%B8%89&age=25(URL 编码)

# application/json
curl -d '{"name":"张三","age":25}' \
     -H "Content-Type: application/json" \
     https://api.example.com

# multipart/form-data(文件上传)
curl -F "avatar=@photo.jpg" \
     -F "name=张三" \
     https://api.example.com/upload

@文件读取

bash 复制代码
# 从文件读取请求体
curl -d @request.json https://api.example.com

# 从标准输入读取
echo '{"test":true}' | curl -d @- https://api.example.com

-o/-O/-w:输出控制

bash 复制代码
# -O:使用远程文件名保存
curl -O https://example.com/file.zip  # 保存为 file.zip

# -o:指定文件名
curl -o myfile.zip https://example.com/file.zip

# -w:自定义输出格式(提取特定信息)
curl -w "HTTP Code: %{http_code}\nTime: %{time_total}s\n" \
     -o /dev/null -s \
     https://example.com

# 常用格式变量
curl -w "
HTTP: %{http_code}
DNS: %{time_namelookup}s
Connect: %{time_connect}s
TTFB: %{time_starttransfer}s
Total: %{time_total}s
Size: %{size_download} bytes
Speed: %{speed_download} B/s
" -o /dev/null -s https://example.com

这些时间变量对性能诊断非常重要:

  • time_namelookup:DNS 解析时间
  • time_connect:TCP 连接建立时间
  • time_starttransfer:首字节到达时间(TTFB)
  • time_total:总传输时间

高级技巧:网络调试实战

1. 抓取完整的请求/响应

bash 复制代码
# 使用 --trace 查看完整的网络交互
curl --trace-ascii debug.txt https://api.example.com

# 查看生成的文件
cat debug.txt
# 输出包含:
# == Info: DNS resolution timing
# => Send header: GET / HTTP/1.1
# => Send data: {"test":true}
# <= Recv header: HTTP/1.1 200 OK
# <= Recv data: {"result":"success"}

2. SSL/TLS 证书调试

bash 复制代码
# 查看证书详情
curl -v https://example.com 2>&1 | grep -A 10 "SSL certificate"

# 跳过证书验证(仅测试用)
curl -k https://self-signed.example.com

# 指定 CA 证书路径
curl --cacert /path/to/ca.pem https://internal.example.com

# 指定客户端证书(双向 SSL)
curl --cert client.pem --key client-key.pem https://mtls.example.com
bash 复制代码
# 保存 Cookie 到文件
curl -c cookies.txt https://example.com/login

# 使用保存的 Cookie
curl -b cookies.txt https://example.com/dashboard

# 同时读写 Cookie(保持会话)
curl -b cookies.txt -c cookies.txt https://example.com/action

# 直接设置 Cookie(不使用文件)
curl -b "session=abc123; user=test" https://example.com

4. 重定向跟踪

bash 复制代码
# -L:跟随重定向(默认不跟随)
curl -L https://example.com/redirect

# --max-redirs:限制重定向次数
curl -L --max-redirs 3 https://example.com

# 查看 Location 头(不跟随)
curl -I https://example.com/redirect
# HTTP/1.1 302 Found
# Location: https://example.com/new-location

5. 超时控制

bash 复制代码
# --connect-timeout:连接超时
curl --connect-timeout 5 https://example.com

# --max-time:总超时(包括下载)
curl --max-time 10 https://example.com/large-file.zip

# --speed-time + --speed-limit:传输速度阈值
# 如果 10 秒内速度低于 1000 B/s,则中止
curl --speed-time 10 --speed-limit 1000 https://example.com/file.zip

性能优化 :批量请求

并发请求

curl 本身不支持并发,但可以配合 xargs:

bash 复制代码
# 使用 xargs 并发请求(-P 指定并发数)
cat urls.txt | xargs -P 10 -I {} curl -s {} > output.txt

# 或者使用 GNU parallel
parallel -j 10 curl -s {} ::: $(cat urls.txt)

管道模式

curl 支持 --parallel(curl 7.66.0+):

bash 复制代码
# 批量下载(并发)
curl --parallel --parallel-immediate \
     -O https://example.com/file1.zip \
     -O https://example.com/file2.zip \
     -O https://example.com/file3.zip

断点续传

bash 复制代码
# -C -:自动检测断点位置
curl -C - -O https://example.com/large-file.zip

# 如果中断后重新运行,会从断点继续下载

常见陷阱与解决方案

1. URL 中的特殊字符

bash 复制代码
# 错误:& 被 shell 解释为后台运行
curl https://api.example.com?key=value&other=param

# 正确:用引号包裹 URL
curl "https://api.example.com?key=value&other=param"

# 或转义 &
curl https://api.example.com?key=value\&other=param

2. 二进制数据传输

bash 复制代码
# 发送二进制数据(不要用 -d,它会处理换行符)
curl --data-binary @binary.dat https://api.example.com

# 上传文件(保持原始字节)
curl -T large-file.zip https://api.example.com/upload

3. 大文件内存问题

bash 复制代码
# curl 默认会缓存响应到内存,大文件会占用大量内存
# 解决:使用 -o 直接写入文件,绕过内存缓存
curl -o large-file.zip https://example.com/large-file.zip

4. HTTP/2 和 HTTP/3

bash 复制代码
# 强制使用 HTTP/2
curl --http2 https://example.com

# 尝试 HTTP/3(QUIC)
curl --http3 https://example.com

# 查看实际使用的协议
curl -I -w "Protocol: %{http_version}\n" https://example.com

curl vs wget:如何选择?

特性 curl wget
数据传输 ✓ 上传 + 下载 ✓ 仅下载
协议支持 20+ 种 HTTP/HTTPS/FTP
递归下载 ✓ -r
请求定制 ✓ 灵活 ✗ 有限
库支持 ✓ libcurl ✗ 无
断点续传 ✓ -C - ✓ -c
后台运行 ✓ -b

结论

  • API 调试、数据上传:curl
  • 批量下载、镜像网站:wget

实战脚本示例

API 健康检查脚本

bash 复制代码
#!/bin/bash
URL="https://api.example.com/health"
TIMEOUT=5

RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" \
                 --max-time $TIMEOUT \
                 $URL)

if [ "$RESPONSE" -eq 200 ]; then
    echo "✅ API 正常 (HTTP $RESPONSE)"
    exit 0
else
    echo "❌ API 异常 (HTTP $RESPONSE)"
    exit 1
fi

性能基准测试

bash 复制代码
#!/bin/bash
URL="https://example.com"
ITERATIONS=10

echo "测试 URL: $URL"
echo "测试次数: $ITERATIONS"
echo "---"

for i in $(seq 1 $ITERATIONS); do
    curl -w "第${i}次: %{time_total}s (HTTP %{http_code})\n" \
         -o /dev/null -s \
         $URL
done

总结

curl 核心在于:

  1. 协议无关性:统一的接口处理 20+ 种协议
  2. 底层透明:每个选项对应 libcurl API,可控性极强
  3. 调试友好-v--trace 提供完整的网络交互细节
  4. 脚本友好:与 shell 完美结合,易于自动化

掌握 curl,不仅是学会一个命令,更是理解 HTTP 协议和网络调试的最佳途径。


相关工具cURL 命令转换器 | HTTP 状态码查询 | API 测试工具

相关推荐
A小辣椒6 小时前
TShark:Wireshark CLI 功能
linux
A小辣椒10 小时前
TShark:基础知识
linux
AlfredZhao12 小时前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao1 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334661 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪1 天前
linux 拷贝文件或目录到指定的位置
linux
摇滚侠2 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush42 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5202 天前
Linux 11 动态监控指令top
linux
不会C语言的男孩2 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言