curl 深度教程 / 第 01 章:curl 简介与生态
第 01 章:curl 简介与生态
curl 是互联网基础设施中沉默的巨人——你可能从未直接使用过它,但你每天的网络活动几乎都有它的参与。
1.1 curl 的历史
起源:一个瑞典开发者的业余项目
| 时间 | 事件 |
|---|---|
| 1996 年 | 瑞典开发者 Daniel Stenberg 开始编写一个名为 httpget 的工具 |
| 1998 年 | 更名为 curl(Client URL),添加对 FTP、GOPHER 等协议的支持 |
| 2001 年 | libcurl 库发布,允许其他程序复用 curl 的网络能力 |
| 2008 年 | curl 支持 IPv6 和 HTTP/1.1 Keep-Alive |
| 2013 年 | 引入 HTTP/2 支持(基于 nghttp2) |
| 2018 年 | 支持 HTTP/2 over QUIC 实验性构建 |
| 2020 年 | curl 7.72.0 发布,累计超过 200 个命令行选项 |
| 2023 年 | curl 8.0 发布,象征性版本号升级 |
| 2024 年 | Daniel Stenberg 获得 IETF 杰出贡献奖 |
curl 的"无处不在"
curl 可能是被编译、嵌入和调用最广泛的网络库之一:
- 📱 Android 和 iOS 中的网络栈底层有 libcurl 的身影
- 🌐 PHP 的
file_get_contents()底层可使用 libcurl - 🐍 Python 的
pycurl绑定直接调用 libcurl - 🐳 Docker 官方镜像自带 curl,用于健康检查
- 🚗 汽车、路由器、智能家电 的固件中嵌入了 libcurl
- 🎮 PlayStation、Xbox 游戏机使用 libcurl 进行网络通信
📊 据统计,curl 的代码被嵌入到了 超过 100 亿台设备中。
1.2 设计理念
curl 的设计遵循几个核心原则:
命令行优先(CLI-First)
curl 的首要身份是一个 命令行工具。这意味着:
# 一切都是命令行参数
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name": "张三"}' \
-o response.json
- 可组合:可与
grep、jq、xargs等工具管道组合 - 可脚本化:无需交互,适合 CI/CD 自动化
- 可复现:一个命令就是一个完整的操作记录
协议无关(Protocol-Agnostic)
curl 不只是 HTTP 工具,它支持超过 25 种协议:
| 协议 | 说明 | 示例 |
|---|---|---|
| HTTP/HTTPS | 最常用 | curl https://example.com |
| FTP/FTPS | 文件传输 | curl ftp://ftp.example.com/file.txt |
| SCP/SFTP | 安全文件传输 | curl sftp://user@host/file |
| SMTP/SMTPS | 发送邮件 | curl smtp://mail.example.com |
| POP3/POP3S | 接收邮件 | curl pop3://mail.example.com |
| IMAP/IMAPS | 邮件访问 | curl imaps://mail.example.com |
| LDAP/LDAPS | 目录服务 | curl ldap://ldap.example.com |
| TFTP | 简单文件传输 | curl tftp://tftp.example.com/file |
| MQTT | 物联网消息 | curl mqtt://broker.example.com |
| DICT | 字典查询 | curl dict://dict.org/d:hello |
| RTSP/RTP | 流媒体 | curl rtsp://media.example.com/stream |
| GOPHER | 早期互联网协议 | curl gopher://gopher.example.com |
不做假设(No Assumptions)
curl 遵循 “你告诉它什么,它就做什么” 的原则:
- 不会自动跟踪重定向(除非你指定
-L) - 不会自动显示下载进度(除非输出到终端且非
-s) - 不会自动保存响应(除非你指定
-o或-O) - 不会自动压缩(除非你指定
--compressed)
这种"保守"的设计使得 curl 在脚本中行为可预测。
1.3 curl vs wget vs httpie
这是开发者最常问的问题之一。以下是详细对比:
功能对比表
| 特性 | curl | wget | httpie |
|---|---|---|---|
| 主要用途 | 数据传输 | 文件下载 | API 调试 |
| 交互式使用 | 中等 | 低 | 极佳 |
| 脚本化能力 | 极佳 | 良好 | 中等 |
| 协议支持 | 25+ | HTTP/FTP | HTTP/HTTPS |
| 递归下载 | ❌ | ✅ | ❌ |
| 彩色输出 | ❌ | ❌ | ✅ |
| JSON 语法高亮 | ❌ | ❌ | ✅ |
| 断点续传 | ✅(-C -) | ✅ | ❌ |
| HTTP/2 | ✅ | ❌ | ✅(插件) |
| 上传能力 | ✅ | 有限 | ✅ |
| Cookie 支持 | ✅ | ✅ | ✅ |
| 代理支持 | ✅ | ✅ | ✅ |
| 系统预装 | ✅ | 部分 | ❌ |
| 依赖项 | 无(静态编译) | 无 | Python + 依赖 |
| Docker 镜像中 | ✅ | 部分 | ❌ |
| 学习曲线 | 中等 | 低 | 低 |
curl vs wget:核心差异
# curl:精确控制每个请求
curl -X POST https://api.example.com/data \
-H "Authorization: Bearer token" \
-H "Content-Type: application/json" \
-d '{"key": "value"}' \
-o result.json
# wget:递归下载整站
wget --mirror --convert-links \
--no-parent https://example.com/docs/
选择 curl 当你需要:
- 精确控制 HTTP 请求的每个细节
- 调试 API 端点
- 在脚本中进行数据传输
- 测试服务端行为
选择 wget 当你需要:
- 递归下载整个网站
- 后台断点续传大文件
- 简单的镜像操作
curl vs httpie:API 调试场景
# curl 发送 JSON POST
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name": "张三", "age": 30}'
# httpie 发送同样的请求(更简洁)
http POST https://api.example.com/users name=张三 age:=30
选择 httpie 当你需要:
- 频繁手动调试 REST API
- 喜欢彩色格式化输出
- 想要更简洁的 JSON 输入语法
- 开发和演示环境
选择 curl 当你需要:
- 生产环境脚本
- 最大兼容性(curl 几乎预装在所有 Unix 系统中)
- 精确控制每个请求细节
- 高性能批量请求
1.4 适用场景
场景 1:API 开发与测试
# 测试 REST API 端点
curl -s https://api.example.com/users/1 | jq .
# 测试认证流程
curl -s -X POST https://api.example.com/auth \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "secret"}' \
-w "\nHTTP Status: %{http_code}\n"
场景 2:CI/CD 健康检查
# 在部署脚本中检查服务是否就绪
for i in $(seq 1 30); do
if curl -sf http://localhost:8080/health > /dev/null; then
echo "服务已就绪!"
exit 0
fi
echo "等待服务启动... ($i/30)"
sleep 2
done
echo "服务启动超时!"
exit 1
场景 3:文件下载与分发
# 下载大文件,显示进度,失败自动重试
curl -L -O -C - --retry 3 --retry-delay 5 \
https://releases.example.com/v2.0/app.tar.gz
场景 4:Webhook 调试
# 向 webhook 端点发送测试事件
curl -X POST https://hooks.example.com/deploy \
-H "Content-Type: application/json" \
-H "X-Webhook-Secret: my-secret" \
-d '{"event": "push", "branch": "main", "commit": "abc123"}'
场景 5:服务器诊断
# 检查 TLS 证书
curl -vI https://example.com 2>&1 | grep -E "expire|subject|issuer"
# 检查 HTTP/2 支持
curl -sI --http2 https://example.com 2>&1 | head -1
# 测量 TTFB(首字节时间)
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s\n" \
https://example.com
1.5 curl 的生态系统
curl 不仅仅是一个命令行工具,它有一个完整的生态系统:
curl 生态系统
├── curl ← 命令行工具(你正在学的)
├── libcurl ← C 语言库(curl 的底层)
├── curl-config ← 编译配置工具
├── CA cert bundle ← 证书包(ca-certificates)
├── curl-for-win ← Windows 预编译版本
├── curl-fuzzer ← 模糊测试工具
└── 第三方绑定
├── pycurl (Python)
├── php-curl (PHP)
├── node-libcurl (Node.js)
├── curl-rust (Rust)
├── ruby-curb (Ruby)
├── go-curl (Go)
└── libcurl-java (Java)
1.6 curl 的版本命名
理解 curl 的版本命名有助于你选择合适的版本:
| 版本 | 含义 |
|---|---|
| 7.x | 经典版本线(1998-2023) |
| 8.0+ | 新版本线(2023 年起,象征性升级) |
| 7.85.0+ | 支持 URL 内联语法(url=user:pass@host) |
| 7.75.0+ | 支持 URL globbing 和变量 |
# 查看当前版本
curl --version
# 输出示例:
# curl 8.5.0 (x86_64-pc-linux-gnu) libcurl/8.5.0 OpenSSL/3.1.4 ...
# Protocols: dict file ftp ftps gopher ...
# Features: alt-svc AsynchDNS brotli GSS-API HSTS HTTP2 HTTPS-proxy ...
注意事项
- curl 不是 wget:curl 默认将输出打印到 stdout,不会自动保存文件
- 引号很重要:URL 中的
&、?、=等字符在 shell 中有特殊含义,必须用引号包裹 - 版本差异:不同操作系统预装的 curl 版本差异很大,注意检查版本
- 安全更新:curl 经常发布安全更新,建议保持较新版本
# ❌ 错误:URL 未加引号,& 被 shell 解释为后台运行
curl https://api.example.com/data?page=1&size=10
# ✅ 正确:URL 用引号包裹
curl "https://api.example.com/data?page=1&size=10"
扩展阅读
- Everything curl — 免费在线电子书
- curl 的诞生故事 — Daniel Stenberg 的博客
- curl Wikipedia 页面
- HTTPie 官方文档
- GNU wget 手册
- libcurl 支持的所有协议
📖 下一章:第 02 章:安装与编译 — 了解如何在各平台安装 curl,以及如何从源码编译自定义版本。