起因
每天调几十次 curl 测 API,命令越写越长:
curl -X POST https://api.example.com/v1/users \
-H 'Authorization: Bearer xxx' \
-H 'Content-Type: application/json' \
-d '{"email":"[email protected]","name":"Alice","age":30}' \
-i -v -s \
| jq .
curl 强大但 verbose。下面几个现代工具针对"开发期 API 调试"做了大幅
简化。
httpie:人友好的 curl 替代
brew install httpie # 或 apt install httpie / pipx install httpie
http --version
用法
# GET
http https://api.example.com/users/1
# 自动 pretty-print JSON + 语法高亮
# POST + JSON body
http POST https://api.example.com/users \
email=[email protected] name=Alice age:=30
# - key=value 是字符串
# - key:=value 是 number/bool/null 等 (JSON 类型)
# - 自动加 Content-Type: application/json
# Authorization
http https://api.example.com/me Authorization:'Bearer xxx'
# 或:
http -A bearer -a xxx https://api.example.com/me
# 上传文件
http POST https://api.example.com/upload file@./photo.jpg
# 看 request / response 头(默认显示 response 头)
http -v POST ... # -v 把 request 也打印
http -h POST ... # 只 print headers
http -p Hb POST ... # 控制哪些部分打印 (H=header, b=body)
# session(保存 cookie + auth)
http --session=alice POST https://api.example.com/login email=[email protected]
http --session=alice https://api.example.com/me # 复用 cookies
输出:
HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 24 May 2026 10:00:00 GMT
Server: nginx
{
"id": 42,
"name": "Alice",
"email": "[email protected]"
}
JSON 自动格式化 + 高亮,headers 区分颜色,整体一眼看清。
xh:Rust 重写的 httpie,启动更快
brew install xh
# 或 cargo install xh
xh --version
API 几乎完全跟 httpie 兼容:
xh POST https://api.example.com/users email=[email protected] name=Alice
httpie 启动 ~150ms(Python),xh ~10ms(Rust)。频繁使用差异明显。
我个人现在用 xh > httpie > curl 这个偏好。
hurl:把 API 测试写成可重放脚本
brew install hurl
.hurl 文件:
# login.hurl
POST https://api.example.com/login
{
"email": "[email protected]",
"password": "secret"
}
HTTP 200
[Asserts]
jsonpath "$.token" exists
jsonpath "$.user.email" == "[email protected]"
[Captures]
token: jsonpath "$.token"
GET https://api.example.com/me
Authorization: Bearer {{token}}
HTTP 200
[Asserts]
jsonpath "$.email" == "[email protected]"
POST https://api.example.com/posts
Authorization: Bearer {{token}}
{
"title": "Hello",
"body": "..."
}
HTTP 201
[Asserts]
jsonpath "$.title" == "Hello"
[Captures]
post_id: jsonpath "$.id"
GET https://api.example.com/posts/{{post_id}}
HTTP 200
跑:
hurl login.hurl
# 全部 assertion 通过 = exit 0
# 否则 exit 非 0
# 输出更详细
hurl --verbose --variables-file vars.env login.hurl
# 测试 mode
hurl --test login.hurl
适用:
- E2E API 测试 + CI
- API 回归验证(每次部署后自动跑)
- 复制粘贴前端测试用的 request 序列
完整功能:query params、文件上传、cookies、多文件 chain、报告输出(JSON/JUnit/HTML)。
curl 仍然适合什么
curl 不会消失:
- 服务器 minimal 环境(绝对默认安装)
- 调试 TLS / HTTP 协议级(
-v --trace) - script / Dockerfile / CI 里(无依赖、跨平台)
- 二进制下载 / 长文件传输
httpie / xh 是"开发期人调用",curl 是"机器调用"。
与 Postman / Insomnia 对比
GUI 工具优势:
- 历史记录 + 文档化
- 团队共享 collection
- 自动 OAuth 流程
CLI 工具优势:
- 嵌入 shell 脚本
- 版本控制(.hurl 进 git)
- 远程服务器跑(无 GUI 环境)
我个人:探索 / 团队共享用 Bruno(GUI 但
本地文件存储 + git 友好);shell 直接调用 xh / hurl。
bonus: jq / jaq 处理 JSON 响应
xh https://api.example.com/users | jq '.[] | select(.age > 30) | .name'
# jaq(jq 的 Rust 重写,10x 快)
brew install jaq
xh https://api.example.com/users | jaq -r '.[] | .email'
-r raw 输出(无引号),适合 pipe 进 xargs。
实战 workflow
测一个新 API:
# 1. 探索 - GET
xh https://api.example.com/users/1
# 2. 试 POST
xh POST https://api.example.com/users name=Bob email=[email protected]
# 3. 满意后写成 hurl 脚本
cat > tests/create-user.hurl <<'EOF'
POST https://api.example.com/users
{ "name": "{{name}}", "email": "{{email}}" }
HTTP 201
[Asserts]
jsonpath "$.id" exists
EOF
# 4. CI 里跑
hurl --test --variables-file ci-vars.env tests/*.hurl
xh 探索 → hurl 固化。一条 pipeline。
效果
迁移后:
- 日常 API 调试输入字符 -70%(不用
-X-H-d) - API 回归测试用 hurl 脚本进 git,新员工看脚本就懂用法
- ci 端 hurl 测试 10 个 endpoint 用 5 秒
- 团队同 hurl 文件分享,跨 OS / 跨编辑器一致
踩过的坑
-
shell 解析
:和=:
bash http POST url 'description=hello, world' # 逗号正常 http POST url 'tags:=["a","b"]' # JSON 数组要 quote
特殊字符记得 quote。 -
httpie 默认 redirect 不跟:
-F/--follow才跟 redirect。
xh 默认跟。 -
session 文件路径:
~/.config/httpie/sessions/。换机器要带,
或--session-read-only临时用。 -
hurl asserts 严格类型:
jsonpath "$.count" == 5和== "5"
不同(数字 vs 字符串)。看 API 返回类型对照写。 -
不支持 WebSocket / gRPC:纯 HTTP。WebSocket 用 wscat / websocat;
gRPC 用 grpcurl。
登录后参与评论。