Skip to content
返回博客
教程

curl 命令速查表:40+ HTTP 与 API 实战示例

完整的 curl 命令速查表:GET/POST、请求头、Bearer 认证、文件上传下载、API 测试,40+ 复制即用示例。附在线工具助你调试。

14 分钟

curl 命令速查表:40+ HTTP 与 API 实战示例

你 SSH 跳了三层进到一台 staging 机器,某个 API 返回的结果不对,而机器上唯一装好的 HTTP 客户端就是 curl。又或者你在读一个 CI 脚本,它对服务做健康检查,你想搞清楚 -fsS 到底干了什么。再或者同事在 Slack 里贴了一行命令,你得改改拿来用。curl 哪里都有,可它的 flag 短得没人记得全。

这份 curl 速查表就是为这些时刻准备的。开头是一张日常高频 flag 的速查表,后面是覆盖各类常见任务的复制即用命令示例:GET 和 POST 请求、发送请求头、Bearer token 认证、上传与下载文件,还有脚本里的 API 测试。每条命令都用了一个真实、能跑的 URL(httpbin.orgapi.example.com 占位符),粘贴就能试。这些行为都依据官方 curl 文档和当前的 HTTP 语义标准 RFC 9110

速查:你真正会用到的 curl flag

日常 curl 的九成都集中在十来个 flag 上。把这张表收藏好,后面会用能跑的 curl 命令示例逐个展开。

Flag含义示例
-X设置 HTTP 方法curl -X DELETE https://api.example.com/items/42
-H添加请求头(可重复)curl -H "Accept: application/json" https://httpbin.org/get
-d发送请求体(隐含 POST)curl -d "name=alice" https://httpbin.org/post
--json发送 JSON 请求体并设置 JSON 请求头curl --json '{"id":1}' https://httpbin.org/post
-F发送 multipart 表单字段/文件curl -F "file=@report.pdf" https://httpbin.org/post
-o将输出保存到指定文件名curl -o page.html https://example.com
-O用远程文件名保存curl -O https://example.com/archive.zip
-L跟随重定向curl -L https://httpbin.org/redirect/2
-uBasic 认证 user:passcurl -u alice:s3cret https://httpbin.org/basic-auth/alice/s3cret
-i在输出中包含响应头curl -i https://httpbin.org/get
-I仅获取响应头(HEAD)curl -I https://example.com
-v详尽模式:显示请求 + TLS 握手curl -v https://example.com
-s静默(无进度条)curl -s https://httpbin.org/get
-w传输后写出变量curl -s -o /dev/null -w "%{http_code}" https://example.com
-b发送 cookie(字符串或文件)curl -b cookies.txt https://httpbin.org/cookies
-c将收到的 cookie 存入 jar 文件curl -c cookies.txt https://httpbin.org/cookies/set/a/1
-k跳过 TLS 证书校验curl -k https://self-signed.example.com
--http2请求 HTTP/2curl --http2 https://example.com
--http3请求 HTTP/3(QUIC)curl --http3 https://example.com
-T用 PUT 上传文件curl -T backup.tar https://api.example.com/files/backup.tar
--data-urlencode对请求体字段做 URL 编码curl --data-urlencode "q=hello world" https://httpbin.org/get -G
--max-time限制整个传输的最长秒数curl --max-time 10 https://example.com
--connect-timeout限制建立连接的最长秒数curl --connect-timeout 5 https://example.com
--retry失败时重试 N 次curl --retry 3 https://example.com
--limit-rate限制传输带宽curl --limit-rate 2M -O https://example.com/big.iso

curl 语法基础:一个请求拆开看

一条 curl 命令由二进制本身、若干 flag 和一个 URL 组成。URL 放在 flag 之前或之后都行,curl 不在乎顺序。它在乎的是哪些 flag 会隐含某个方法或请求体,因为它们之间会相互影响。

一个简单的 GET 请求

不带方法 flag 时,curl 发送 GET。完整命令就这么一行:

curl https://httpbin.org/get

httpbin 会把你的请求以 JSON 形式原样回显,拿来测试很方便。加查询字符串的方式和在浏览器里一样:

curl "https://httpbin.org/get?page=2&sort=desc"

给 URL 加引号。一个裸露的 & 会让 shell 把命令丢到后台运行,并悄悄吞掉它后面的所有内容,这是 curl 最常见的错误之一,后面的「陷阱」一节还会讲到。

看响应:响应体、响应头,或两者一起看

默认情况下 curl 只打印响应体。三个 flag 改变你看到的内容:

# Body + status line + response headers
curl -i https://httpbin.org/get

# Headers only — sends a HEAD request, no body
curl -I https://example.com

# Full trace: request line, request headers, TLS handshake, response
curl -v https://example.com

想看响应体、顺带瞄一眼 Content-Type 或某个 Set-Cookie,用 -i。想在不下载资源的前提下检查它(文件大小、最后修改时间、重定向目标),用 -I。出了问题、想看清 curl 到底发了什么,用 -v

跟随重定向

curl 不会主动跟随重定向,除非你要求它这么做。访问一个返回 301302 的 URL 却不带 -L,你拿到的是重定向响应本身,而不是目标页面:

# Stops at the 302, prints nothing useful
curl https://httpbin.org/redirect/1

# Follows the chain to the final 200
curl -L https://httpbin.org/redirect/1

如果你不确定一个请求为什么最终落到某处,-IL 会显示每一跳的状态码。这些状态码各自的含义,以及为什么 301302 不能互换,参见 HTTP 状态码速查表

用 curl 发各种 HTTP 方法(GET、POST、PUT、PATCH、DELETE)

curl 会根据你的 flag 自动选定方法:-d--json 隐含 POST,纯 URL 隐含 GET。只有当你需要的方法与所发送的请求体不匹配时,才用 -X

带查询参数的 GET

一旦取值里含有空格或 &,手工拼查询字符串就很容易出错。-G flag 告诉 curl 把 --data-urlencode 字段作为正确编码的查询字符串追加到 URL 上:

curl -G https://httpbin.org/get \
  --data-urlencode "q=hello world" \
  --data-urlencode "tag=c++"

这会生成 ?q=hello%20world&tag=c%2B%2B,curl 替你做好了百分号编码,省得你发出一个坏掉的 URL。

POST:表单数据 vs JSON

一个 curl post request 常见有两种形态。先看表单编码,也就是经典的 HTML 表单请求体:

curl -d "name=alice&role=admin" https://httpbin.org/post

-d 会设置 Content-Type: application/x-www-form-urlencoded 并替你把方法切换为 POST。对于 JSON API,则改发 JSON:

curl -d '{"name":"alice","role":"admin"}' \
  -H "Content-Type: application/json" \
  https://httpbin.org/post

这种写法还有更清爽的版本,下一节就会讲。

PUT 与 PATCH

PUT 替换整个资源,PATCH 只更新其中一部分。PUT 是幂等的,发送两次后状态保持一致。

# Replace the whole resource
curl -X PUT -d '{"name":"alice","role":"owner"}' \
  -H "Content-Type: application/json" \
  https://api.example.com/users/7

# Update one field
curl -X PATCH -d '{"role":"owner"}' \
  -H "Content-Type: application/json" \
  https://api.example.com/users/7

DELETE

DELETE 通常不带请求体,所以只要 -X 就够了:

curl -X DELETE https://api.example.com/users/7

发送请求头与 JSON 请求体

真实的 API 工作大多绕着请求头和 JSON 转。主要靠两个 flag:-H--json

-H 自定义 curl 请求头

-H 添加一个请求头,需要多少次就重复多少次。设置 AcceptAuthorization、自定义 X- 头和请求 ID 都靠它:

curl https://httpbin.org/headers \
  -H "Accept: application/json" \
  -H "X-Request-Id: 9f3c1a" \
  -H "User-Agent: my-cli/1.0"

要移除某个 curl 本来会发送的默认请求头,给它一个空值(-H "User-Agent:")。要发送一个无值的请求头,用分号(-H "X-Empty;")。

POST JSON:-d vs 现代的 --json flag

从 curl 7.82 开始,发送 JSON curl post request 最地道的方式就是 --json。它一次做三件事:设置 Content-Type: application/json、设置 Accept: application/json,再原样发送请求体。

# Verbose, old way — three pieces to keep in sync
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"name":"alice"}' \
  https://httpbin.org/post

# Modern equivalent
curl --json '{"name":"alice"}' https://httpbin.org/post

--json 可以重复,会自动拼接,--json @file.json 则从文件读取请求体。任何 JSON API 都优先用它。

Content-Type 与 Accept

415 和 406 错误就出在这两个请求头上。Content-Type 描述你发送的请求体,Accept 表明你想要什么回来。向只接受表单数据的端点发送 JSON,你会得到 415 Unsupported Media Type。向只支持 JSON 的 API 索要 XML,你可能会拿到 406 Not Acceptable。(这些状态码在 HTTP 状态码速查表里有详解。)

如果响应回来是一大坨压缩过的 JSON,用 JSON 格式化工具把它美化,或者直接管道给 jq 提取某个字段:

curl -s https://httpbin.org/json | jq '.slideshow.title'

想看完整的 jq 过滤器集合,比如选择、映射、重塑 API 响应,参见 jq 速查手册

用 curl 做认证

几乎所有 API 的认证都不出这四种:basic 认证、bearer token、API key 和 cookie。

Basic 认证(-u user:pass

-u 会发送一个 HTTP Authorization: Basic 请求头,凭据经 Base64 编码:

curl -u alice:s3cret https://httpbin.org/basic-auth/alice/s3cret

省略密码(-u alice),curl 会提示你输入,免得密码落进 shell 历史记录。

Bearer token 与 OAuth

大多数现代 API 用的是 curl bearer token:放在 Authorization 请求头里的 OAuth 2.0 访问令牌或 API token。curl 提供了一个简写 --oauth2-bearer,效果等同于手写该请求头:

# Explicit header
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0In0.abc" \
  https://api.example.com/me

# Shorthand
curl --oauth2-bearer "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0In0.abc" \
  https://api.example.com/me

如果后端拒绝了 token,别急着怪 curl,先用 JWT 解码器解码,检查 exp(过期时间)、aud(受众)和 iss(签发者)这些 claim,过期或受众不对的 token 才是常见原因。

API key(请求头 vs 查询参数)

有些 API 要 key 放在请求头里,有些要放在查询参数里。请求头更安全,因为 URL 会泄漏到日志和浏览器历史里:

# Preferred: key in a header
curl -H "X-API-Key: sk_live_a1b2c3" https://api.example.com/data

# Less safe: key in the URL (ends up in access logs)
curl "https://api.example.com/data?api_key=sk_live_a1b2c3"

-c 写出一个 cookie jar,-b 把它读回来。要在多个请求间携带会话,靠的就是这两个:

# Log in and save the session cookie
curl -c jar.txt -d "user=alice&pass=s3cret" https://httpbin.org/cookies/set/session/abc123

# Reuse it on the next call
curl -b jar.txt https://httpbin.org/cookies

安全提示: token 和凭据只应出现在 HTTPS 连接上,TLS 会加密请求头,纯 HTTP 不会。别把机密直接写在命令行上,那样它们会落进 shell 历史和 ps 输出。改用 -H @authfile 从文件读取请求头,或者从环境变量取值(-H "Authorization: Bearer $TOKEN")。

下载与上传文件

curl 的名字「client URL」就说明了搬运文件是它的本职工作。下载和上传各有几个值得记住的 flag。

下载:-O vs -o vs -C -

-O(大写 O)用远程文件名保存文件,-o(小写)让你自己选名字,-C - 从断点续传一个没下完的文件:

# Save as the remote filename: archive.zip
curl -O https://example.com/downloads/archive.zip

# Save under a name you pick
curl -o backup.zip https://example.com/downloads/archive.zip

# Resume an interrupted download
curl -C - -O https://example.com/downloads/archive.zip

# Follow redirects to the real file (common with CDNs)
curl -OL https://example.com/latest/archive.zip

curl download file 下载藏在重定向后面的内容,加上 -L,发布页和 CDN 链接几乎总会重定向。

上传:-T vs -F

-TPUT 上传文件,把原始字节当作请求体发送,对象存储和 REST 文件端点常这么用。-F 发送一个 multipart/form-data 请求,跟浏览器处理文件输入框时用的格式一样:

# PUT raw bytes
curl -T report.pdf https://api.example.com/files/report.pdf

# multipart/form-data upload (note the @ prefix)
curl -F "file=@report.pdf" -F "title=Q2 report" https://httpbin.org/post

@ 前缀告诉 curl 去读文件的内容。没有它,-F "file=report.pdf" 发出去的是字面字符串 report.pdf,而不是文件本身。

--data-urlencode 与百分号编码

当一个值里含有空格、&= 或非 ASCII 字符时,-d 会原样发出去,把你的请求搞坏。--data-urlencode 会正确编码它:

# Wrong: the & splits the body, the space is invalid
curl -d "q=hello world&filter=a&b" https://httpbin.org/post

# Right: each field is percent-encoded
curl --data-urlencode "q=hello world" \
  --data-urlencode "filter=a&b" \
  https://httpbin.org/post

如果你想搞懂那些 %20%26 序列的含义,或者调试一个被双重编码的值,把它粘贴到 URL 编码解码工具,或者读一读 URL 编码与解码指南里的字节级讲解。

API 测试与检查响应

curl 在脚本和 CI 里特别好用,因为 -w 把传输的方方面面都暴露出来,退出码又让失败能被检测到。

只取状态码

只想拿到 HTTP 状态码,用 -o /dev/null 丢掉响应体,再用 -w 打印状态码:

curl -s -o /dev/null -w "%{http_code}\n" https://httpbin.org/status/204
# → 204

这是任何 curl api testing 健康检查的核心。要解读拿到的数字,HTTP 状态码速查表把每个区间都讲了。

耗时拆解

-w 提供了一系列耗时变量,让你看清时间花在哪里:DNS、TCP 连接、TLS,还是服务器本身:

curl -s -o /dev/null \
  -w "dns=%{time_namelookup}s connect=%{time_connect}s tls=%{time_appconnect}s total=%{time_total}s\n" \
  https://example.com
# → dns=0.004s connect=0.021s tls=0.058s total=0.142s

time_appconnect 偏高说明问题出在 TLS,time_starttransfer 偏高说明后端响应慢。

静默但仍报告错误

-s 隐藏进度条,可它同时也会把错误信息藏起来,这是脚本里的一个坑。把它和 -S 搭配用,curl 就会在成功时保持安静,遇到失败时照样报告:

curl -sS https://api.example.com/health

CI/脚本中的 curl:遇 HTTP 错误就失败

默认情况下,哪怕遇到 404500,curl 也会以 0 退出,因为传输本身成功了。健康检查里这恰恰是你不想要的。-f(fail)让 curl 在 HTTP 错误时以非零退出,这样你的流水线就能抓到它们:

# Fails the build if the endpoint returns 4xx/5xx
curl -fsS https://api.example.com/health || exit 1

-fsS(fail、silent、show-errors)是健康检查的标准组合。想要更丰富的诊断,--fail-with-body(curl 7.76+)会在退出前把错误响应也打印出来。

超时与重试

一个永远挂起的健康检查比快速失败更糟。给每个脚本化请求加上 --max-time(整个传输的上限)和 --connect-timeout(仅连接建立的上限):

# 连接 5 秒、总计 10 秒后放弃
curl --connect-timeout 5 --max-time 10 -fsS https://api.example.com/health

网络不稳定时,--retry 会以指数退避重试失败的传输。默认只重试瞬时故障(超时、5xx);加 --retry-all-errors 可一并重试连接被拒:

# 最多重试 3 次,每次之间退避
curl --retry 3 --retry-all-errors --max-time 30 -fsS https://api.example.com/health

脚本拉取大文件又不想占满带宽时,--limit-rate 限制带宽——--limit-rate 2M 把速度压到 2 MB/s。

用 curl 处理 HTTP/1.1、HTTP/2 与 HTTP/3

curl 通过 TLS 上的 ALPN 协商 HTTP 版本。需要测试某条特定协议路径时,可以强制指定版本。

--http2--http3

# Request HTTP/2 (falls back to 1.1 if unavailable)
curl --http2 https://example.com

# Request HTTP/3 over QUIC
curl --http3 https://example.com

HTTP/3 跑在 QUIC 之上,需要 TLS 1.3。只有当你的 curl 是用支持 HTTP/3 的后端构建的,并且服务器通过 Alt-Svc 请求头宣告它时,它才会生效。运行 curl --version,确认 features 那一行里出现了 HTTP3,没有的话 --http3 会报错。

详尽的 TLS/ALPN 信息

-v 会显示协商出的协议和 TLS 握手,想确认某个版本是否真的生效,就靠它:

curl -v --http2 https://example.com 2>&1 | grep -i "ALPN\|HTTP/2"
# → * ALPN: server accepted h2
# → > GET / HTTP/2

在握手输出里找 ALPN: server accepted h2(HTTP/2)或 h3(HTTP/3)。

8 个常见的 curl 陷阱(及修复方法)

这八个坑迟早会绊倒每个人。

  1. 单引号 vs 双引号。 双引号让 shell 展开 $VARS,单引号则原样传递一切。JSON 请求体用单引号,这样 $! 不会被解释:curl --json '{"price":"$5"}'。当你想要展开时才用双引号:-H "Authorization: Bearer $TOKEN"

  2. -d 不做 URL 编码。 -d 值里的空格或 & 会破坏请求体。任何还没编码的值,都改用 --data-urlencode

  3. -d 配上多余的 -X POST -d 本身已经隐含了 POST。写 -X POST -d ... 无害,只是多余;更糟的是 -X GET -d ... 会让 GET 带上请求体,有些服务器会被它搞懵。让请求体 flag 自己去定方法就好。

  4. 从文件读取时忘了 @ -d @body.json 读取文件,-d body.json 发出去的是字面文本 body.json-F "file=@upload.png"-F "file=upload.png" 也是同一个坑。

  5. 一遇到证书错误就上 -k -k 禁用 TLS 校验,会盖住真正的问题,比如证书过期、主机名不符、缺中间证书。该修的是根因:用 --cacert ca.pem 安装 CA,或者更新系统信任库。-k 只留给你完全掌控的自签名开发服务器。

  6. -s 吞掉错误。 静默模式会在脚本里把失败藏起来。始终用 -sS,让错误照样冒出来。

  7. URL 里的 [ ] { } 被通配展开。 curl 会把 [1-5]{a,b} 当作 URL 范围/列表。一个含字面方括号的 URL(数组查询参数里很常见,比如 arr[]=1)会被它搞乱。用 -g 关掉通配:curl -g "https://api.example.com/items?id[]=1&id[]=2"

  8. 请求头大小写与重复。 HTTP 请求头名称不区分大小写,但同一个头发送两次通常会两个都发出去,有的服务器取第一个,有的取最后一个,有的干脆拒绝。要覆盖某个默认值(比如 User-Agent),用 -H 一次性设好,别指望靠顺序。

curl vs wget vs HTTPie:该用哪个

三者都通过 HTTP 取数据,但各自擅长不同的活儿。下面是 curl vs wget(外加 HTTPie)的决策一览:

任务curlwgetHTTPie
快速 API 调用/调试出色有限出色
JSON 请求体良好(--json别扭出色(原生)
递归整站下载/镜像不行出色(-r不行
续传 + 重试大文件下载良好(-C -出色(内置)不行
脚本/CI(退出码、-w出色良好良好
默认漂亮、带色彩的输出不行不行出色
几乎处处预装经常很少

简单说:做 API 调试和写脚本用 curl(它哪里都有,-w 也没对手),想在自己机器上看可读的 JSON 用 HTTPie,镜像站点或带自动重试地批量下载文件用 wget

常见问题

curl 是做什么用的?

curl 是一个命令行工具,通过 HTTP、HTTPS、FTP 等众多协议在服务器之间传输数据。开发者用它调用和调试 API、下载和上传文件,以及在脚本和 CI 流水线里跑健康检查。

如何用 curl 发送 POST 请求?

表单数据用 -d,JSON 用 --jsoncurl --json '{"name":"alice"}' https://httpbin.org/post。这两个 flag 都会自动把方法设为 POST,所以不需要 -X POST

如何在 curl 中添加请求头?

-H "Name: value",多个请求头就重复它:curl -H "Accept: application/json" -H "X-Request-Id: 9f3c1a" https://httpbin.org/headers-H 能传多少次都行。

如何用 curl 发送 bearer token?

传一个 Authorization 请求头:curl -H "Authorization: Bearer YOUR_TOKEN" https://api.example.com/me,或者用简写 --oauth2-bearer YOUR_TOKEN。token 只在 HTTPS 上发送,调试时用 JWT 解码器解码它们。

如何用 curl 下载文件?

-O 保留远程文件名,或者用 -o name 自选名字:curl -O https://example.com/archive.zip。加 -L 跟随重定向,加 -C - 续传被中断的下载。

如何用 curl 只看 HTTP 状态码?

丢掉响应体,只打印状态码:curl -s -o /dev/null -w "%{http_code}" https://example.com。这是脚本里做健康检查的标准写法。

curl 和 wget 有什么区别?

curl 传输单个资源,默认写到 stdout,很适合 API 调用和写脚本。wget 专精下载,包括递归镜像和自动重试。做 API 测试用 curl,批量下载文件用 wget。

Windows 上有 curl 吗?

有。curl 随 Windows 10(build 1803+)和 Windows 11 一起发布,在命令提示符和 PowerShell 里都能以 curl 调用。要注意 PowerShell 过去把 curl 别名指向 Invoke-WebRequest,所以如果 flag 行为不对劲,就显式调用 curl.exe

小结

curl 只要记住一点点就够用了:顶部那张 flag 表覆盖了你大多数会敲的命令,剩下的就是知道哪些 flag 隐含方法、哪些需要加引号,以及哪些会在脚本里坑你(说的就是你,裸露的 -s)。把这份 curl 速查表开在终端旁边。如果你更喜欢可视化地组合命令,可以用我们的 cURL 命令构建器 来生成。

API 工作流的下一步就在手边。用 curl 发出请求,用 HTTP 状态码速查表读懂回来的内容,再用 JSON 格式化工具美化 JSON,或者用 jq 速查手册切分它。想看完整的选项列表,curl 手册写得极其详尽,MDN 的 HTTP 参考则解释了每个方法和请求头背后的语义。

标签: curl http rest-api command-line developer-reference