curl 命令详解与参数实测(Ubuntu 22.04)
curl 7.81.0 全参数实测:默认输出与 -s/-S 静默策略、-o/-O 落盘、-sI 响应头逐项解读、-v 调试三段结构、-L 重定向跟随与 num_redirects、-d/-X POST 与 JSON 头体、-H 自定义头、-u Basic 认证 401/200 双形态、-x 代理 rc=7、-w 分段耗时指标、--max-time rc=28、-C - 断点续传 md5 校验、-k 自签证书 rc=60、-A/-e 请求伪装与退出码 6/7/22/28 对照
curl 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 curl 的每一个常用参数——默认输出与
-s/-S静默策略、-o/-O落盘方式、-I响应头逐项解读、-i头体同显、-v调试三段结构、-L重定向跟随、-d/-XPOST 请求、-H自定义头、-uBasic 认证、-x代理、-w格式化指标、--max-time超时、-C -断点续传、-k自签证书、-A/-e请求伪装,以及退出码 6/7/22/28 的错误形态对照,全部命令与回显已在 Ubuntu 22.04(curl 7.81.0)实测通过。
一、环境信息
本节列出本文所有实测所依赖的环境、测试数据与本地服务,便于读者按同规格复现。
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- curl 版本:curl 7.81.0(Release-Date: 2022-01-05,Ubuntu 22.04 官方仓库默认版本,
curl --version实测) - 公网目标:httpbin.org(可正常访问,用于重定向/POST/认证等回显服务)、www.baidu.com
- 本地测试服务(用 Python 的 http.server 模块模拟,均监听在 127.0.0.1):
| 服务 | 端口 | 用途 |
|---|---|---|
| 文件服务(支持 Range 请求,返回 Accept-Ranges: bytes) | 8000 | 默认下载、-I/-i 头解读、-O、-w、-C - 断点续传 |
| 慢响应服务(收到请求后延迟 5 秒再应答) | 8001 | --max-time 超时实测 |
| 自签 HTTPS 服务(证书 CN=localhost) | 8443 | -k 跳过证书校验实测 |
- 演示目录:
/root/demo/curl/,测试数据清单:
| 文件 | 大小 | 用途 |
|---|---|---|
| site/index.html | 356 字节 | HTML 页面(默认输出演示) |
| site/hello.txt | 31 字节 | 小文本下载目标 |
| site/big.bin | 10,485,760 字节(10 MiB) | 断点续传 |
| site/medium.bin | 3,145,728 字节(3 MiB) | -w 速率统计 |
| site/data.gz、site/notes.txt、site/style.css、site/img/logo.txt | 各数十字节 | 组合场景素材 |
| cert.pem / key.pem | 自签证书对 | 8443 端口 TLS 服务 |
💡 技术拓展:curl 与 wget 都是命令行传输工具,选型分工对比如下:
维度 curl wget 定位 「传数据」的瑞士军刀,协议多达 25 种(HTTP/FTP/SMTP/SFTP…) 专精 HTTP/FTP 的「下载器」 递归下载 不支持 原生支持( -r递归抓整站)上传 强项( -T、-d、-F表单)仅 FTP 上传 API 调试 强项( -v/-H/-X/-u细粒度控制)基本不支持 断点续传 -C --c(对本地文件更智能)默认行为 输出到标准输出 直接落盘 简单记忆:调接口用 curl,下东西/搬站用 wget。本文是 curl 专题,wget 的对应实测见本专栏《wget 命令详解与参数实测(Ubuntu 22.04)》。
二、命令概览
2.1 语法与测试数据准备
curl 的语法是 curl [options...] <url>,不给任何选项时它把 URL 的响应体原样打印到标准输出——这既是它作为「管道友好」工具的优点,也让初学者在终端里被整屏 HTML 与进度表吓到。本文所有实测基于一个本地小站点与 httpbin.org 公网回显服务。
准备演示数据与本地文件服务(http.server 默认监听 8000 端口,以 site/ 为站点根):
$ mkdir -p /root/demo/curl/site/img /root/demo/curl/dl && cd /root/demo/curl && printf 'hello curl\nline two\nline three\n' > site/hello.txt && printf 'notes text\n' > site/notes.txt && echo gzcontent > site/data.gz && echo logo > site/img/logo.txt
$ dd if=/dev/urandom of=/root/demo/curl/site/big.bin bs=1M count=10 status=none && dd if=/dev/urandom of=/root/demo/curl/site/medium.bin bs=1M count=3 status=none && ls -l /root/demo/curl/site
total 13340
-rw-r--r-- 1 root root 10485760 Oct 15 19:56 big.bin
-rw-r--r-- 1 root root 10 Oct 15 19:56 data.gz
-rw-r--r-- 1 root root 31 Oct 15 19:56 hello.txt
drwxr-xr-x 2 root root 4096 Oct 15 19:56 img
-rw-r--r-- 1 root root 356 Oct 15 20:16 index.html
-rw-r--r-- 1 root root 3145728 Oct 15 19:56 medium.bin
-rw-r--r-- 1 root root 11 Oct 15 19:56 notes.txt
-rw-r--r-- 1 root root 212 Oct 15 20:16 page2.html
-rw-r--r-- 1 root root 34 Oct 15 19:56 style.css
启动文件服务并验证(服务进程挂在后台,日志落 /tmp/http8000.log):
$ cd /root/demo/curl/site && nohup python3 -m http.server 8000 --bind 0.0.0.0 >/tmp/http8000.log 2>&1 &
$ sleep 1 && curl -s http://localhost:8000/hello.txt
hello curl
line two
line three
💡 说明:python3 自带的 http.server 不支持 Range 分块请求,而 3.14 的断点续传需要服务器配合返回
206 Partial Content。实测时在 8000 端口换用了带 Range 支持的简易 Python 服务(响应头会多一行Accept-Ranges: bytes,见 3.3/3.4 的真实回显);读者复现时用 nginx 等常规 Web 服务器也能得到同样形态的响应头。
2.2 --help 输出(分类式菜单,节选主干)
curl 7.81 的 --help 改成了分类菜单式,只显示最常用的 12 个选项并提示分类入口,全量回显如下:
$ curl --help | head -45
Usage: curl [options...] <url>
-d, --data <data> HTTP POST data
-f, --fail Fail silently (no output at all) on HTTP errors
-h, --help <category> Get help for commands
-i, --include Include protocol response headers in the output
-o, --output <file> Write to file instead of stdout
-O, --remote-name Write output to a file named as the remote file
-s, --silent Silent mode
-T, --upload-file <file> Transfer local FILE to destination
-u, --user <user:password> Server user and password
-A, --user-agent <name> Send User-Agent <name> to server
-v, --verbose Make the operation more talkative
-V, --version Show version number and quit
This is not the full help, this menu is stripped into categories.
Use "--help category" to get an overview of all categories.
For all options use the manual or "--help all".
全量选项要 --help all,实测共 245 行,以下节选开头 30 行(字母序排列的长选项全貌):
$ curl --help all | wc -l
245
$ curl --help all | sed -n '1,30p'
Usage: curl [options...] <url>
--abstract-unix-socket <path> Connect via abstract Unix domain socket
--alt-svc <file name> Enable alt-svc with this cache file
--anyauth Pick any authentication method
-a, --append Append to target file when uploading
--aws-sigv4 <provider1[:provider2[:region[:service]]]> Use AWS V4 signature authentication
--basic Use HTTP Basic Authentication
--cacert <file> CA certificate to verify peer against
--capath <dir> CA directory to verify peer against
-E, --cert <certificate[:password]> Client certificate file and password
--cert-status Verify the status of the server cert via OCSP-staple
--cert-type <type> Certificate type (DER/PEM/ENG)
--ciphers <list of ciphers> SSL ciphers to use
--compressed Request compressed response
--compressed-ssh Enable SSH compression
-K, --config <file> Read config from a file
--connect-timeout <fractional seconds> Maximum time allowed for connection
--connect-to <HOST1:PORT1:HOST2:PORT2> Connect to host
-C, --continue-at <offset> Resumed transfer offset
-b, --cookie <data|filename> Send cookies from string/file
-c, --cookie-jar <filename> Write cookies to <filename> after operation
--create-dirs Create necessary local directory hierarchy
--create-file-mode <mode> File mode for created files
--crlf Convert LF to CRLF in upload
--crlfile <file> Use this CRL list
--curves <algorithm list> (EC) TLS key exchange algorithm(s) to request
-d, --data <data> HTTP POST data
--data-ascii <data> HTTP POST ASCII data
--data-binary <data> HTTP POST binary data
--data-raw <data> HTTP POST data, '@' allowed
💡 说明:
--help all245 行覆盖了 curl 的全部能力面;按类别检索可先curl --help看类别名,再curl --help <category>缩小范围。本文第三章只实测日常高频参数。
2.3 版本信息(特性行解读)
curl --version 输出三行:主行、发布日期、协议与特性清单,逐段解读价值很大:
$ curl --version
curl 7.81.0 (x86_64-pc-linux-gnu) libcurl/7.81.0 OpenSSL/3.0.2 zlib/1.2.11 brotli/1.0.9 zstd/1.4.8 libidn2/2.3.2 libpsl/0.21.0 (+libidn2/2.3.2) libssh/0.9.6/openssl/zlib nghttp2/1.43.0 librtmp/2.3 OpenLDAP/2.5.20
Release-Date: 2022-01-05
Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps mqtt pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS brotli GSS-API HSTS HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM NTLM_WB PSL SPNEGO SSL TLS-SRP UnixSockets zstd
- 主行:curl 与 libcurl 版本 7.81.0、平台三元组 x86_64-pc-linux-gnu,后跟各后端库(TLS 用 OpenSSL 3.0.2、压缩支持 brotli/zstd、SSH 用 libssh、HTTP/2 用 nghttp2);
- Protocols 行:该构建支持的 25 种协议,写脚本前先确认目标协议在列(如 scp/sftp 就依赖 libssh);
- Features 行:
HTTP2表示支持 h2、AsynchDNS表示 DNS 解析异步(不阻塞并发)、Largefile支持大于 2 GiB 文件、SSL支持 HTTPS、IDN支持国际化域名。
💡 要点:排障时第一件事就是
curl --version——HTTPS 报错先看有没有SSL特性,HTTP/2 问题先看有没有HTTP2特性,不同发行版裁剪出的能力差异很大。
三、参数逐项实测
3.1 默认输出与 -s 静默
curl 默认把响应体打印到标准输出,配合管道可截取任意片段。-s(silent)同时抑制进度表和错误消息,是脚本场景的标准起手式:
$ curl -s http://localhost:8000/ | head -8
<!DOCTYPE html>
<html><head><title>Demo Site</title><link rel="stylesheet" href="http://localhost:8000/style.css"></head>
<body><h1>Hello Demo Site</h1>
<p><a href="http://localhost:8000/page2.html">Page 2</a></p>
</body></html>
$ curl -s http://localhost:8000/hello.txt
hello curl
line two
line three
💡 要点:非交互(输出重定向)场景下 curl 的进度表一般不刷新,但 HEAD 形态(
-I不带-s)实测仍会输出一帧统计;-s能把这类噪音一并关掉。注意-s连错误消息也吞掉,排障时要用-sS(见 3.5)。
3.2 -o 写入指定文件 / -O 按远端名保存
-o 自定义本地文件名,-O 直接用 URL 路径里的文件名落地(URL 必须带文件名部分,否则报错):
$ cd /root/demo/curl && curl -s -o saved-index.html http://localhost:8000/; echo rc=$?; ls -l saved-index.html
rc=0
-rw-r--r-- 1 root root 229 Oct 15 19:56 saved-index.html
$ cd /root/demo/curl/dl && curl -s -O http://localhost:8000/hello.txt; echo rc=$?; ls -l
rc=0
total 4
-rw-r--r-- 1 root root 31 Oct 15 19:56 hello.txt
💡 要点:
-o /dev/null是「只测不通、不留文件」的经典写法,配合-w输出指标(见 3.12);批量下载时-O与--remote-name-all搭配可一次拉多个 URL。注意-O遇到以/结尾的 URL 会失败,因为提取不出文件名。
3.3 -I 只取响应头(逐头解读)
-I 发出 HEAD 请求,只返回响应头。这是「接口健康检查」最常用的一招:
$ curl -sI http://localhost:8000/
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.10.12
Date: Thu, 15 Oct 2026 20:26:38 GMT
Content-type: text/html
Content-Length: 356
Last-Modified: Thu, 15 Oct 2026 20:16:43 GMT
逐头解读:
HTTP/1.0 200 OK:协议版本 + 状态码 + 短语。SimpleHTTP 按 HTTP/1.0 应答,生产服务器通常是HTTP/1.1 200 OK或HTTP/2 200;Server: SimpleHTTP/0.6 Python/3.10.12:服务器软件指纹(安全加固时常把这里改掉);Date: Thu, 15 Oct 2026 20:26:38 GMT:服务器响应时间,一律 GMT 时区;Content-type: text/html:正文 MIME 类型,注意这个服务把该头写成小写Content-type(HTTP 头名大小写不敏感);Content-Length: 356:正文字节数,脚本可用来做文件大小预检;Last-Modified: Thu, 15 Oct 2026 20:16:43 GMT:文件最后修改时间,配合If-Modified-Since做缓存协商。
💡 要点:不带
-s的curl -I在非交互输出下实测仍会额外打印一帧进度表统计(% Total / % Received ...两行),加-s即可消除。-I适合探测存在性、跳转、缓存策略而不下载正文;但部分服务器对 HEAD 与 GET 行为不一致,需要精确复现 GET 时用-s -o /dev/null -w '%{http_code}'。
3.4 -i 响应头 + 响应体一起输出
-i(include)在正文前面带上响应头,适合一次性确认「头与体」的对应关系:
$ curl -s -i http://localhost:8000/hello.txt
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.10.12
Date: Thu, 15 Oct 2026 19:56:40 GMT
Content-Type: application/octet-stream
Content-Length: 31
Accept-Ranges: bytes
hello curl
line two
line three
💡 要点:
-i与-I的区别一目了然——-i是 GET 请求带响应头输出,-I是 HEAD 请求只有响应头。注意此回显里Accept-Ranges: bytes表示服务器支持分块请求,这正是 3.14 断点续传能工作的前提。
3.5 -s 吞错误与 -S 恢复错误显示
-s 静默模式会连 curl 自己的错误消息一起吞掉,只留下退出码;加 -S(show-error)可在静默的同时保留错误消息——这是脚本里「安静但可排障」的正确组合:
$ curl -s http://no-such.invalid; echo rc=$?
rc=6
$ curl -sS http://no-such.invalid; echo rc=$?
curl: (6) Could not resolve host: no-such.invalid
rc=6
💡 要点:生产脚本推荐固定写法
curl -sS ...; rc=$?——成功时零噪音,失败时错误进日志、退出码进监控。
3.6 -v 调试(* 信息 / > 请求 / < 响应 三段)
-v 是 curl 最强排障参数,输出按前缀分三类:* 是连接/协议层信息,> 是发出的请求行与请求头,< 是收到的状态行与响应头:
$ curl -sv http://localhost:8000/hello.txt 2>&1 | head -30
* Trying 127.0.0.1:8000...
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /hello.txt HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: SimpleHTTP/0.6 Python/3.10.12
< Date: Thu, 15 Oct 2026 19:56:40 GMT
< Content-Type: application/octet-stream
< Content-Length: 31
< Accept-Ranges: bytes
<
{ [31 bytes data]
* Closing connection 0
hello curl
line two
line three
💡 要点:三段结构正好对应一次 HTTP 交互的三个阶段——连上了吗(
*)、发了什么(>)、收到什么(<)。-v输出走 stderr,所以示例里用2>&1合并;要更细的十六进制轨迹用--trace-ascii 文件。
3.7 -L 跟随重定向
默认 curl 收到 3xx 就停,-L 让它带着新地址继续请求(最多 50 跳)。先看不做跟随时的 302 原始响应:
$ curl -sI -m 15 http://httpbin.org/redirect/2 | head -6
HTTP/1.1 302 FOUND
Date: Thu, 15 Oct 2026 19:56:42 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 247
Connection: keep-alive
Server: gunicorn/19.9.0
加 -L 后跟随 2 跳到达终点 /get,配合 -w 变量验证:
$ curl -s -o /dev/null -m 15 -w 'final=%{url_effective} code=%{http_code} redirects=%{num_redirects}\n' -L http://httpbin.org/redirect/2
final=http://httpbin.org/get code=200 redirects=2
💡 要点:
-L的最佳搭档是-w的三个变量:url_effective(最终 URL)、http_code(最终状态码)、num_redirects(跳了几次)。排查「跳转后丢了 POST 方法」问题时,记住 curl 默认对 301/302 会把 POST 降级为 GET,--post301/--post302可保持。
3.8 -d POST 表单与 -X POST 显式指定方法
-d 会自动把请求方法设为 POST,并默认发送 application/x-www-form-urlencoded 表单(httpbin.org 的 /post 会把收到的请求原样回显成 JSON):
$ curl -s -m 15 -d 'name=qzuo&score=99' http://httpbin.org/post | head -12
{
"args": {},
"data": "",
"files": {},
"form": {
"name": "qzuo",
"score": "99"
},
"headers": {
"Accept": "*/*",
"Content-Length": "18",
"Content-Type": "application/x-www-form-urlencoded",
-X POST 只显式指定方法,配合 -H 改 Content-Type 即可发 JSON:
$ curl -s -m 15 -X POST -H 'Content-Type: application/json' -d '{"city":"beijing"}' http://httpbin.org/post | head -10
{
"args": {},
"data": "{\"city\":\"beijing\"}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Content-Length": "18",
"Content-Type": "application/json",
"Host": "httpbin.org",
💡 要点:
-d数据里出现@file时会读文件内容作为请求体(-d @body.json),想原样发送@用--data-raw。-X本身不改变语义,只强制方法名——没有-d的-X POST发出的是空 body 的 POST,初学者常因此踩坑。
3.9 -H 自定义请求头
-H '名字: 值' 逐个添加请求头,可重复多次;httpbin.org 的 /headers 会回显收到的全部请求头:
$ curl -s -m 15 -H 'X-Trace-Id: trace-001' -H 'Accept: application/json' http://httpbin.org/headers
{
"headers": {
"Accept": "application/json",
"Host": "httpbin.org",
"User-Agent": "curl/7.81.0",
"X-Amzn-Trace-Id": "Root=1-6ad12fff-41ed3b1443f5fef45d0a3a26",
"X-Trace-Id": "trace-001"
}
}
💡 要点:
-H也能用来覆盖默认头(如-H 'User-Agent: xxx'等价-A)或删除头(-H 'Host:'去掉 Host)。调试网关鉴权时,-H "Authorization: Bearer <token>"是与-uBasic 并列的常用形态。
3.10 -u Basic 认证(200 与 401 双形态)
-u 用户:密码 发送 HTTP Basic 认证。用 httpbin.org 的 /basic-auth/<user>/<passwd> 验证:凭据正确返回认证成功 JSON:
$ curl -s -m 15 -u admin:q1w2e3r4 https://httpbin.org/basic-auth/admin/q1w2e3r4
{
"authenticated": true,
"user": "admin"
}
凭据错误时是标准的 401 形态(响应体几乎为空,靠状态码判断):
$ curl -s -m 15 -o /dev/null -w 'code=%{http_code}\n' -u admin:wrong-pass https://httpbin.org/basic-auth/admin/q1w2e3r4
code=401
💡 要点:不传
-u直接请求受保护资源,会得到 401 与WWW-Authenticate头(可用-i看到);加-u后 curl 自动完成 Basic 编码。密码在命令行明文可见,脚本里更稳妥的写法是-u admin让 curl 交互式提示输入,或用--netrc。
3.11 -x 走代理(无可用代理时的报错形态)
-x [协议://]主机:端口 指定代理。实测指向一个不存在的代理端口(127.0.0.1:1),观察失败形态:
$ curl -sS -x http://127.0.0.1:1 http://localhost:8000/hello.txt; echo rc=$?
curl: (7) Failed to connect to 127.0.0.1 port 1 after 0 ms: Connection refused
rc=7
💡 要点:
-x后的地址是代理的地址,目标 URL 不变;curl 会先与代理建连再转发目标请求(HTTPS 目标走 CONNECT 隧道)。反向记忆:错误消息里 "Failed to connect to <代理IP> port <代理端口>" 就说明卡在代理握手这一步。内网直连场景若环境变量http_proxy被误设,可用--noproxy '*'临时绕开。
3.12 -w 格式化输出(http_code / time_total / size_download)
-w '模板' 在传输结束后按模板输出指标,配合 -o /dev/null 组成「零落盘测速器」。实测本地 3 MiB 文件:
$ curl -s -o /dev/null -w 'http_code=%{http_code} time_total=%{time_total}s size_download=%{size_download} speed_download=%{speed_download}B/s\n' http://localhost:8000/medium.bin
http_code=200 time_total=0.001439s size_download=3145728 speed_download=2186051424B/s
💡 要点:
-w支持 50+ 变量,高频的有%{http_code}、%{time_total}(总耗时)、%{time_namelookup}(DNS 解析耗时)、%{time_connect}(TCP 建连耗时)、%{time_starttransfer}(首字节耗时,TTFB)、%{size_download}、%{speed_download}。分段看耗时就能定位「慢在 DNS、慢在建连还是慢在服务端」——回环环境 time_total 仅 1.4ms,公网目标通常在几十到几百 ms 量级。
3.13 --max-time 超时截断(rc=28)
--max-time 限制整次传输的最长秒数(支持小数),超时立刻断开,退出码 28。对延迟 5 秒的本地慢响应服务实测:
$ curl -s --max-time 2 http://localhost:8001/slow; echo rc=$?
rc=28
💡 要点:
--max-time管「整次传输」(DNS+建连+传输全程),--connect-timeout只管「TCP 建连」。生产脚本两者都要设:curl --connect-timeout 3 --max-time 10,避免对端挂起时脚本无限等待。rc=28 与 rc=7 的区别是「连上了但没传完」与「根本没连上」。
3.14 -C - 断点续传(Range 实测)
-C - 让 curl 从本地已有文件的大小处继续下载(自动发 Range: bytes=<offset>- 请求)。先模拟「下了一半」——用 -r 只取前 2 MiB:
$ cd /root/demo/curl && curl -s -r 0-2097151 -o part.bin http://localhost:8000/big.bin; echo rc=$?; ls -l part.bin
rc=0
-rw-r--r-- 1 root root 2097152 Oct 15 19:56 part.bin
-C - 续传剩余 8 MiB,一次到位:
$ cd /root/demo/curl && curl -s -C - -o part.bin http://localhost:8000/big.bin; echo rc=$?; ls -l part.bin site/big.bin
rc=0
-rw-r--r-- 1 root root 10485760 Oct 15 19:56 part.bin
-rw-r--r-- 1 root root 10485760 Oct 15 19:56 site/big.bin
md5 校验证明续传结果与源文件逐字节一致:
$ cd /root/demo/curl && md5sum part.bin site/big.bin
760c6c33bdb859bafacf7959a42ef5b0 part.bin
760c6c33bdb859bafacf7959a42ef5b0 site/big.bin
💡 要点:断点续传三要素——服务器支持 Range(响应头
Accept-Ranges: bytes)、中断时保留半截文件、续传用-C -。若服务器不支持 Range,curl 会报(33) HTTP server doesn't seem to support byte ranges,此时只能整文件重下。
3.15 -k 跳过证书校验(自签 HTTPS 实测)
对自签证书的 HTTPS 服务,默认校验会失败(rc=60),-sS 拿到完整错误消息:
$ curl -sS https://localhost:8443/hello.txt; echo rc=$?
curl: (60) SSL certificate problem: self-signed certificate
More details here: https://curl.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
rc=60
加 -k 跳过校验后正常通信:
$ curl -sk https://localhost:8443/hello.txt; echo rc=$?
hello curl
line two
line three
rc=0
💡 要点:
-k(--insecure)等于关闭中间人防护,只用于自签环境的临时调试。生产做法是把自签 CA 装入信任链(--cacert my-ca.pem)。rc=60 是证书无法验证,rc=51/35 则分别是证书校验其他失败与 SSL 握手失败,排障时先看错误号。
3.16 -A 自定义 User-Agent 与 -e 自定义 Referer
-A 改 User-Agent、-e 改 Referer,两个最常见的「请求伪装」参数,同样由 httpbin.org 回显验证:
$ curl -s -m 15 -A 'QzuoBot/1.0' http://httpbin.org/user-agent
{
"user-agent": "QzuoBot/1.0"
}
$ curl -s -m 15 -e 'https://www.example.com/source' http://httpbin.org/headers | grep -i referer
"Referer": "https://www.example.com/source",
💡 要点:部分网站对默认 UA
curl/7.81.0做拦截,-A 'Mozilla/5.0'可绕开;-e用于调试防盗链。两者都等价于-H的对应头(-H 'User-Agent: ...'/-H 'Referer: ...'),只是语义化更好。
3.17 退出码对照(6 / 7 / 22 / 28 节选)
curl 退出码有近百个,脚本高频使用的是下面四个,实测形态汇总:
| 退出码 | 含义 | 实测触发命令 | 实测错误消息 |
|---|---|---|---|
| 6 | 无法解析主机 | curl -sS http://no-such.invalid | curl: (6) Could not resolve host: no-such.invalid |
| 7 | 连接被拒/连不上 | curl -sS http://127.0.0.1:9 | curl: (7) Failed to connect to 127.0.0.1 port 9 after 0 ms: Connection refused |
| 22 | HTTP 页面错误(配合 -f) | curl -sf http://localhost:8000/nothing | (静默,rc=22) |
| 28 | 操作超时 | curl -s --max-time 2 http://localhost:8001/slow | (静默,rc=28) |
逐条实测回显(6 号已在 3.5、7 号已在 3.11、28 号已在 3.13 出现):
$ curl -s http://127.0.0.1:9; echo rc=$?
rc=7
$ curl -sf http://localhost:8000/nothing; echo rc=$?
rc=22
💡 要点:
-f(fail)让 4xx/5xx 不输出错误页正文、直接以 rc=22 退出——脚本判断 HTTP 错误必须加-f,否则 404 页面也会被当作「成功」写进文件。
四、实战示例
4.1 接口体检:状态码 + 耗时 + 大小一次拿全
健康检查脚本的标准输出形态,一个命令给出全部关键指标:
$ curl -s -o /dev/null -w 'code=%{http_code} dns=%{time_namelookup}s connect=%{time_connect}s ttfb=%{time_starttransfer}s total=%{time_total}s size=%{size_download}\n' http://localhost:8000/index.html
code=200 dns=0.000010s connect=0.000065s ttfb=0.000522s total=0.000570s size=356
(回环环境各段耗时可忽略不计;公网接口的 dns/connect 段通常在 ms 至几十 ms,ttfb 反映服务端处理耗时。)判断逻辑:code 非 2xx/3xx 看 -f 与服务端日志;ttfb 占 total 比例高说明服务端慢;connect 段高说明网络/建连慢。
4.2 JSON 接口自测:方法 + 头 + 体三要素
模拟一次带鉴权头的 JSON 接口调用,验证服务端回显:
$ curl -s -m 15 -X POST -H 'Content-Type: application/json' -H 'Authorization: Bearer token-abc123' -d '{"city":"beijing"}' http://httpbin.org/post | head -10
{
"args": {},
"data": "{\"city\":\"beijing\"}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Authorization": "Bearer token-abc123",
"Content-Length": "18",
"Content-Type": "application/json",
要点:-X 定方法、-H 定头、-d 定体,三者组合即可覆盖绝大多数 REST 接口自测场景。
4.3 大文件限速下载与断点续传
共享带宽环境下用 --limit-rate 礼貌限速,实测把 3 MiB 文件限到 1 MB/s(总耗时约 3 秒、均速约 1.06 MB/s):
$ curl -s -o /dev/null --limit-rate 1M -w 'code=%{http_code} time_total=%{time_total}s size_download=%{size_download} speed_download=%{speed_download}B/s\n' http://localhost:8000/medium.bin
code=200 time_total=2.956995s size_download=3145728 speed_download=1063825B/s
传输中断后用 -C - 续传收尾(复用 3.14 的两步流程),并用 md5 校验结果完整性:
$ cd /root/demo/curl && curl -s -r 0-2097151 -o part.bin http://localhost:8000/big.bin && curl -s -C - -o part.bin http://localhost:8000/big.bin; echo rc=$?; md5sum part.bin site/big.bin
rc=0
760c6c33bdb859bafacf7959a42ef5b0 part.bin
760c6c33bdb859bafacf7959a42ef5b0 site/big.bin
要点:-C - 前必须保证本地半截文件还在;瞬时网络抖动可交给 --retry 3 --retry-delay 2 自动重试。
4.4 自签 HTTPS 环境临时调试
内网自签服务(管理后台、内部网关)调试时,用 -k 临时绕过校验、-v 看握手细节:
$ curl -sk https://localhost:8443/hello.txt; echo rc=$?
hello curl
line two
line three
rc=0
要点:-k 只解决「证书不可信」;若报 (35) SSL connect error 则是协议/套件不匹配,需要 -v 看握手阶段,并考虑 --tlsv1.2 指定协议版本。
五、注意事项与常见问题
Q1:-s 之后好像什么错误都看不到了?
-s 同时抑制进度表与错误消息(见 3.5)。排障改用 -sS,或干脆去掉 -s 看完整输出。
Q2:-X POST 发出去了,服务端却说没收到参数?
-X 只改方法名不改请求体。没有 -d/-F 的 POST 是空 body;表单要用 -d 'k=v'(form-urlencoded)或 -F 'k=@file'(multipart),JSON 要同时 -H 'Content-Type: application/json'(见 3.8)。
Q3:404 也被当成成功写进文件了?
curl 默认把 4xx/5xx 的错误页正文当普通响应处理(rc=0)。脚本判断 HTTP 状态必须加 -f(rc=22)或显式检查 -w '%{http_code}' 的输出(见 3.17)。
Q4:下载大文件中断了怎么办?
确认服务器支持 Range(curl -sI 看是否有 Accept-Ranges: bytes),保留半截文件后执行 curl -C - -o 文件 URL 续传(见 3.14);服务器不支持 Range 时只能重下。
Q5:自签证书报 (60),能不能长期用 -k?
不能。-k 关闭了服务器身份验证,存在中间人风险。正确做法是 --cacert 指定自签 CA 证书,或将 CA 装入系统信任库(见 3.15)。
Q6:怎么知道慢在哪个环节?
用 -w 的分段耗时变量(见 3.12 与 4.1):dns 段大查 DNS、connect 段大查网络/防火墙、ttfb 段大查服务端处理、total-ttfb 段大查下行带宽。
Q7:-v 的输出太吵,能落盘吗?
-v 输出走 stderr,用 curl -v URL 2>debug.log 落盘;需要含十六进制体的完整轨迹用 --trace-ascii debug.log URL。
Q8:退出码速记?
高频四个:6 解析失败(查 DNS/hosts)、7 连不上(查端口/防火墙/代理)、22 HTTP 错误(配合 -f,查服务端)、28 超时(查 --max-time/对端挂起)。完整表见 man curl 的 EXIT CODES 节。
六、参考链接
- curl(1) 手册页(man7.org):https://man7.org/linux/man-pages/man1/curl.1.html
- curl 官方文档站(全参数与 -w 变量表):https://curl.se/docs/
- curl --help 分类说明(everything curl 教程):https://everything.curl.dev/
- curl 退出码官方列表:https://curl.se/libcurl/c/libcurl-errors.html
- HTTP 状态码参考(RFC 9110):https://datatracker.ietf.org/doc/html/rfc9110
- httpbin.org 回显服务(本文公网实测目标):https://httpbin.org/
- Ubuntu 22.04(jammy)curl(1) 在线手册:http://manpages.ubuntu.com/manpages/jammy/en/man1/curl.1.html