资讯动态

curl命令实战指南:高频用法、进阶技巧与常见报错排查

发布时间:2026/9/15 20:44:14 来源:尧图企业网站定制
说实话curl 这个命令我几乎每天都在用但直到最近帮几个朋友排查问题才发现很多人对它的理解还停留在“下载个文件”这个层面。明明一条命令就能定位接口问题、复现请求、检查证书链、看响应耗时结果愣是在浏览器 F12 和 Postman 之间来回倒腾半天。还有人在脚本里写死curl -k跳过证书校验遇到线上报错又一脸懵。这篇东西不打算写成那种堆满参数表的官方文档而是按我平时排查问题的思路来捋一遍 curl 的高频用法、进阶技巧和常见报错希望你看完能少走点弯路。1. 先搞清楚 curl 到底是个什么工具1.1 一个命令走天下的底层逻辑curl 全称是 Client URL翻译成大白话就是“用命令行的方式发网络请求”。它支持的协议很多日常开发最常用的就是 HTTP/HTTPS但 FTP、SMTP、IMAP 这些它也都能碰。之所以说它是“底层工具”是因为它不依赖任何图形界面直接把请求发出去再把响应原样打到终端里。这一点在今天浏览器、Postman、IDE 自带 HTTP 客户端满天飞的环境下反而成了最大的优势——没有界面所以更容易被脚本调用、被自动化任务集成出问题时也更容易定位到底卡在哪一层。很多人第一次接触 curl是因为搜“Linux 下载文件命令”结果发现curl -O就能把远程文件拉下来。这确实是 curl 的核心能力但它的价值远不止下载。它本质上是一个“裸的 HTTP 客户端”你可以完全控制请求方法、请求头、请求体、证书校验、重定向策略甚至自定义 DNS 解析结果。这意味着什么意味着前端联调时接口报错你不需要拉产品经理、后端、运维一起在群里吵架自己用 curl 模拟一发请求就能判断问题出在参数、鉴权、网关还是服务端逻辑。1.2 curl 和 wget别再用错下载工具了刚接触命令行的人经常问curl 和 wget 到底有什么区别我为什么不直接用 wget 下载这个问题很有代表性。wget 的设计目标是“递归下载”就是那种把整个网站镜像到本地的场景它有非常强的目录抓取能力而且断点续传做得比较好。而 curl 的设计目标是“和服务器交换数据”它更强调对协议的控制力。打个比方wget 像一个大货车擅长整批整批地把货拉回家curl 更像一个瑞士军刀什么都带一点单发请求、上传文件、调试协议、模拟客户端样样都能来。实际使用中我下载文件反而更喜欢 curl因为它默认行为更可控-L是否跟随重定向、-o输出到哪个文件、-C -是否断点续传全部显式控制脚本里不会出幺蛾子。而 wget 下载一个文件时如果碰上服务器返回 302 跳转默认还会留在原地址有时候容易踩坑。所以我的习惯是下载单个文件、调试 API 用 curl做站点镜像、整站抓取用 wget两边互补。1.3 为什么每个开发者的工具箱里都得有 curl这里分享一个我真实的排查经历。朋友在一个数据分析平台做后端某天线上反馈某个接口偶发超时他在服务器上用curl -v -w加了耗时统计一条命令就把问题定位到了上游第三方服务响应慢而不是自己服务的问题。整个过程不超过五分钟。当时我就感慨如果他不熟悉 curl可能得先登录监控平台、翻日志、查链路追踪折腾一圈下来半小时起步。另一个非常适合 curl 的场景是容器环境排查。很多时候你用docker exec进到容器里发现里面既没有 Postman 也没有浏览器甚至连 ping 都没有但 curl 大概率是存在的。用 curl 去探测容器内服务的健康检查接口、检查环境变量是否生效、确认端口是否监听几乎是运维排查的“标准动作”。2. 高频参数逐个拆解这些选项到底在干嘛2.1 先掌握最常用的五个参数我接触过很多把 curl 当“黑盒”用的人参数全靠复制粘贴报错就懵。其实高频参数并不多我建议先把下面这五个吃透-o把响应体写入指定文件比如curl -o page.html http://example.com。注意这个参数是“把响应体保存到文件”和-O大写不一样-O是直接用 URL 末尾的文件名保存。-I只取响应头不取响应体。这个在调试时特别省流量curl -I https://github.com一眼就能看到状态码、Server、Content-Type 这些关键信息。-s静默模式不显示进度条和错误信息。脚本里几乎必加因为进度条会污染日志输出。但它会把错误信息也吞掉所以排查问题时要配合-S一起用-sS组合表示“不显示进度条但保留错误信息”。-v详细模式把请求头、响应头、TLS 握手过程、DNS 解析过程全部打印出来。这是调试的神器后面单独展开讲。-w自定义输出格式常用于统计耗时。比如curl -w DNS解析: %{time_namelookup}s, 连接耗时: %{time_connect}s, 总耗时: %{time_total}s -o /dev/null https://example.com。这里特别说一下-v的输出怎么读。它会把发送给服务器的请求头以开头的行打印出来把服务器返回的响应头以开头的行打印出来中间的*开头的是 TLS 握手、DNS 解析这些过程信息。比如你看到一个* Connected to example.com说明 TCP 连接已经建立看到* SSL connection using TLSv1.3说明 SSL/TLS 握手完成。多读几次-v输出你对网络请求的整个链路会有一个非常直观的感知。2.2 请求控制三件套-X、-H、-d讲完基础的五件套接下来是控制请求的“三件套”这三个参数几乎覆盖了日常接口联调的全部需求。-X用于指定请求方法比如curl -X POST https://api.example.com/users。不过需要注意加-d时 curl 会自动变成 POST所以很多时候不需要显式写-X POST。我见过有人写curl -X GET URL这完全没必要因为 curl 默认就是 GET。而且-X在某些场景会强制覆盖方法比如配合-I时 HEAD 请求可能被覆盖掉反而容易踩坑所以我的习惯是“能用-d、-F隐式指定的方法就不显式写-X”。-H用于添加请求头一次可以带多个比如-H Content-Type: application/json -H Authorization: Bearer xxx。这个参数在模拟认证请求、覆盖默认 User-Agent 时非常有用。有些服务会对非浏览器请求做限制你用curl -H User-Agent: Mozilla/5.0就能绕过。-d用于携带请求体数据最经典的是 POST JSON写法是curl -X POST -H Content-Type: application/json -d {name:curl,type:tool} URL。注意-d默认发送的 Content-Type 是application/x-www-form-urlencoded所以你传 JSON 时必须显式加-H指定类型。2.3 调试和容错-k、--location、--retry这三个参数属于“进阶但极易踩坑”的类型。先说-k它表示跳过 SSL 证书校验。很多人的第一反应是“这个参数好方便一加上就不再报证书错误了”但我要泼一盆冷水它只应该在调试阶段使用生产脚本里用-k等于把安全防线亲手拆了中间人攻击、证书伪造全都不设防。正确做法是下载证书、用--cacert指定信任的根证书或者至少用-k加个注释说明为什么临时跳过。--location缩写是-L表示跟随重定向。默认情况下curl 遇到服务器返回 301/302 是不会自动跳转的只会把跳转响应原样打印出来。如果你访问的 URL 做了跳转比如http://跳到https://必须加-L才能拿到最终的页面。但要注意-L配合 POST 请求时某些场景下 curl 会把 POST 改成 GET这在 OAuth 之类的场景会出问题需要配合--post301、--post302来保持方法。--retry用于网络抖动时的自动重试比如--retry 3 --retry-delay 5 --retry-all-errors。这个在脚本里非常实用因为公网环境难免有瞬断重试能显著提高任务成功率。不过重试次数和间隔要控制好不然雪崩时你的重试就是补刀。2.4 进阶--resolve 自定义域名解析这个参数我单独拎出来讲是因为它实在太强了但知道的人太少。--resolve的语法是--resolve 域名:端口:IP作用是“请求这个域名时不走系统 DNS直接连指定 IP”。什么意思呢比如你在切机房、验证负载均衡配置或者服务器还在迁移 DNS 还没切换你可以用curl --resolve api.example.com:443:192.168.1.10 https://api.example.com/v1/health直接绕过 DNS 解析把请求打到指定的那台机器上。另一个典型用法是本机 hosts 文件被改过了但你不想动系统 hosts就可以用--resolve临时覆盖。我之前排查 CDN 缓存是否生效时也是用这个参数把域名强制解析到源站 IP直接对比缓存节点和源站的响应头差异。一句话这个参数是“临时改 hosts 的命令行版本”而且比改 hosts 更灵活因为它只对这次 curl 命令生效不影响系统其他进程。3. 实战场景curl 在真实开发里怎么用3.1 调试 REST API从 Postman 导出到命令行复现Postman 有个很方便的功能就是把请求导出成 curl 命令。在 Postman 的请求面板里点 Code选择 cURL就能看到等价的命令行。但很多人导出之后只是看看不会反过来用。其实这个功能最有价值的场景是“Bug 复现”你在 Postman 里调某个接口是好的但程序里调就报错这时把 Postman 里的请求导出成 curl在服务器上原样执行一遍就能快速判断是代码的问题、网络的问题还是请求参数的问题。反过来我也经常把 curl 命令粘回 Postman。Postman 直接支持从 curl 导入粘贴curl -X POST -H Content-Type: application/json -d {key:value} URL它会自动解析成图形化请求连请求头都会帮你填好。这个来回切换的习惯非常高效命令行适合快速验证和脚本化图形界面适合构造复杂请求和保存历史记录两者互补。3.2 下载文件与一键安装脚本的幕后原理很多人应该都见过这类命令curl -fSSL https://example.com/install.sh | sh一键安装某个软件。这个模式的三个参数值得拆解一下。-f表示失败时不输出 HTML 错误页面直接返回非零退出码防止把错误页面管道给 shell 执行-S配合-s静默模式使用出错时能输出错误信息-L跟随重定向有些安装包下载地址会先跳转到 CDN。三合一就是“静默下载、自动跟随跳转、出错即停”的稳健下载姿势。为什么很多人觉得这个命令“安装进度太慢”因为-s把进度条屏蔽了终端上看起来像卡住了一样。解决办法是去掉-s参数、加上--progress-bar查看进度或者先单独用curl -fSSL -o install.sh URL把脚本下载下来检查内容无误后再执行这样更安全也更可控。顺便提醒一句任何curl ... | sh的操作都等于把系统的最高权限交给了远程脚本一定要确认来源可信、下载链路是 HTTPS最好先下载到本地看一眼脚本内容再执行。3.3 用 curl 看 SSE 实时数据流SSEServer-Sent Events是服务端单向推送的一种实现方式常用于实时通知、消息流、AI 回复等场景。很多人不知道 curl 可以直接用来观察 SSE 连接是否正常。SSE 的响应头是Content-Type: text/event-stream响应体是一段一段的用curl -N就能“实时”输出这些数据流。-N的作用是禁用缓冲区让输出不被缓冲、及时刷新到终端。我之前调试一个 AI 对话服务的流式输出就是靠curl -N直接看原始 SSE 事件流判断服务端是在逐步推送内容还是憋了一大段一次性吐出来。这里有一个小技巧加上--max-time给整个请求设置超时时间防止连接一直挂着不结束。再配合-H Accept: text/event-stream显式声明你接受流式响应基本就能模拟一个标准的 SSE 客户端了。3.4 在 Shell 脚本里把 curl 变成自动化工具curl 在脚本里的价值体现在“把网络请求变成可编程的一等公民”。最常见的用法是用-f让请求失败时返回非零退出码配合或if做条件判断。比如if curl -fsS -o /tmp/backup.sql https://api.example.com/export; then echo 备份下载成功 else echo 备份下载失败退出码: $? fi这里-f保证了 HTTP 4xx/5xx 状态码会被当作错误处理而不是静默下载一个错误页面。另一个常用技巧是用-w配合-o /dev/null只输出状态码和耗时用于接口健康检查code$(curl -s -o /dev/null -w %{http_code} https://api.example.com/health) if [ $code 200 ]; then echo 服务正常 fi还有一种场景是把 curl 的结果直接赋值给变量配合jq做 JSON 解析。比如请求一个返回 JSON 的接口然后从 JSON 里提取字段token$(curl -s -X POST -H Content-Type: application/json \ -d {username:admin,password:secret} \ https://api.example.com/login | jq -r .token)这种写法比用 Python、Node 写个脚本去发请求轻量得多非常适合临时任务和运维脚本。4. 常见报错逐条拆解从 error 3 到 error 564.1 error 3URL 格式出错最常见的是端口号写错curl: (3) URL rejected: Port number was not a decimal number between 0 and 65535这个报错很经典。意思就是 curl 解析 URL 时发现端口号不是一个合法的十进制数字。常见原因是在 URL 里写了类似http://example.com:abc或者端口号带有中文标点、空格。我见过最离谱的是有人把 URL 从微信聊天记录里复制出来冒号被自动变成了全角字符结果 curl 怎么都解析不过。排查方法很简单先echo $URL看看 URL 变量里到底是什么样的重点检查冒号、斜杠这些特殊字符是不是被转义或替换了。如果是脚本里拼的 URL还要检查变量两侧有没有多余空格。另外URL 里的端口范围是 0 到 65535超过这个范围也会报同样的错。比如手滑写了80880一眼看去像 8080 但其实就是超范围了。4.2 error 7连接被拒绝先检查服务有没有监听curl: (7) Failed to connect to 127.0.0.1 port 7897 after 0 ms: Connection refused这个报错太常见了。翻译一下就是“目标端口拒绝了 TCP 连接”通常有几种原因第一目标服务器上根本没有服务监听这个端口第二服务在监听但监听地址是127.0.0.1只允许本机访问外部访问就被拒了第三防火墙把端口拦了。我的排查顺序是先在目标机器上执行ss -lntp | grep 端口号看端口是否处于 LISTEN 状态、监听地址是什么。如果没有输出说明服务没起来如果有输出但不是0.0.0.0或::说明服务只监听了回环地址。确认端口在监听之后再用curl telnet://目标IP:端口或者nc -vz做一次端口连通性测试逐层定位。注意这类报错如果是连接公网服务出现还要检查本机的防火墙和安全组配置。4.3 error 35 和 error 56TLS 握手与连接中断先看error 35常见的描述是Recv failure: Connection reset by peer意思是 TLS 握手阶段连接被对方重置。这个情况在抓 HTTPS 接口时经常出现原因可能是客户端和服务端的 TLS 版本不兼容、服务器要求的 SNI 和客户端发的不一致或者中间有人拦截了流量。快速判断方法是用-v看握手卡在哪一步如果卡在Client hello之后大概率是版本或证书问题可以试着加--tlsv1.2强制指定版本。再看error 56常见的描述是Recv failure: Connection reset by peer或者GnuTLS recv error。和 error 35 不同error 56 通常发生在 TLS 握手完成之后的 HTTP 请求/响应阶段也就是说连接建立起来了但在传输过程中被对端中断了。常见原因有服务器主动断开空闲连接、文件下载到一半服务端崩了、中间设备比如防火墙做了连接超时清理。Git 在 clone 大仓库时经常报RPC failed; curl 56其实就是这个原因。解决办法通常是关闭压缩、调大缓冲区比如git config --global http.postBuffer 524288000 git config --global http.lowSpeedLimit 0 git config --global http.lowSpeedTime 999999这三个配置的意思是把 HTTP 缓冲区调到 500MB、关闭低速限制让 Git 在处理大仓库时不容易被中断。4.4 git 场景下的 curl 报错Git 在走 HTTPS 协议时底层其实就是封装了 curl所以你会看到很多 Git 报错里带了curl 56、curl 35这样的字眼。比如error: RPC failed; curl 56 GnuTLS recv error (-9): error decoding the received packet这通常是在 clone 大仓库或推送大对象时出现的。原因多半是 HTTP/2 的 multiplexing 和某些代理设备不兼容。解决方法是强制 Git 使用 HTTP/1.1git config --global http.version HTTP/1.1另外error: RPC failed; curl 56 schannel: server closed abruptly这种在 Windows 上更常见因为 Windows 版 Git 默认走的是 Windows 的 schannel TLS 后端有时和 GitLab/GitHub 的 TLS 配置配合不太好。解决办法是切回 OpenSSL 后端git config --global http.sslBackend openssl这两个配置我都在实际项目里验证过能解决大部分 Git 走 HTTPS 协议时的 curl 报错。如果是公司内网的 Git 服务器还可以检查是不是证书链不完整用git config --global http.sslCAInfo /path/to/ca.pem指定内网 CA 证书。4.5 常见错误速查表错误码典型信息常见原因优先排查方向error 3URL rejected: Port number...URL 格式不对端口号非法检查 URL 里的冒号、斜杠、端口范围error 6Could not resolve hostDNS 解析失败检查域名拼写、系统 DNS、hosts 文件error 7Failed to connectTCP 连接被拒绝检查端口监听、防火墙、服务状态error 28Operation timed out请求超时检查网络连通性、服务端负载、--max-timeerror 35Recv failure: Connection reset by peerTLS 握手中断检查 TLS 版本、SNI、中间设备error 56Recv failure: Connection reset by peer传输阶段连接中断检查服务端稳定性、缓冲区、HTTP 版本error 60SSL certificate problem证书校验失败检查证书链、过期时间、CA 配置这张表格并不完整但覆盖了日常开发和运维中最常见的几种。建议你把它截图存一下下次报错直接对号入座。5. 一些实操心得和避坑技巧5.1 下载太慢怎么办回到热词里那个“curl 安装脚本太慢怎么办”的问题。首先要明确curl本身的下载速度取决于网络链路、服务器带宽和协议版本不是调参数就能解决的。常规排查思路是加-v看请求都经过了哪些跳转确认是不是被重定向到了某个速度很慢的节点。其次很多下载慢是 DNS 解析到了不太好用的 IP可以用--resolve手动指定一个已知较快的 IP 来验证是不是这个原因。再次对于大型安装脚本别直接用| sh先下载到本地用curl -C -断点续传断了接着下不浪费之前的流量。我自己遇到这类问题时还会用time_redirect、time_starttransfer这几个耗时指标定位瓶颈。比如curl -s -o /dev/null -w 重定向前耗时: %{time_redirect}s, 首字节耗时: %{time_starttransfer}s, 总耗时: %{time_total}s URL如果首字节耗时很长说明网络往返或服务端处理慢如果首字节快但总耗时很长说明下载带宽受限。5.2 安全使用 curl 的几个习惯第一不要在命令行里直接写账号密码。比如curl -u username:password URL这条命令会出现在 shell history 里。正确做法是用-u username让它交互式输入密码或者用~/.netrc文件配合chmod 600控制权限。第二谨慎使用-k跳过证书校验尤其是涉及生产环境、敏感数据的请求跳过了校验等于裸奔。第三curl ... | sh这种模式要三思你等于把机器的最高权限直接交给了远端脚本。如果一定要用至少先下载到本地、查看脚本内容、确认逻辑无害再执行。5.3 再补几个很实用的小技巧最后分享几个我常在手边用的小技巧。第一个是curl ipinfo.io查出口 IP配合-H Accept: application/json可以看到 IP 归属地、ASN 等详细信息排查网络策略问题很好用。第二个是curl -v https://example.com/ 21 | grep SSL connection快速确认 TLS 版本和加密套件检查服务端是否还在用老旧的 TLSv1.0。第三个是curl -w curl-format.txt URL配合模板文件把耗时、状态码、下载大小全部按固定格式输出适合做批量接口巡检。还有一个比较冷门但很实用的curl --limit-rate 200K URL可以限制下载速率。在测试带宽控制策略、模拟弱网环境时这个参数比在路由器上做限速方便多了。另外--max-time和--connect-timeout一定要养成习惯加上前者限制整个请求的最大耗时后者限制建立连接的最大耗时防止脚本因为某个请求卡死而挂机等待。我在实际使用中最大的体会是curl 的学习曲线其实不陡但它的每个参数背后都对应着一个真实的网络问题。你把参数用熟了等于把网络协议栈的那些概念也跟着过了一遍。与其遇到问题去搜“curl 报错”不如花一个下午把-v的输出读明白把常用的十来个参数组合练熟往后再难缠的网络问题你都会发现自己多了一把趁手的家伙。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价