十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

curl命令行详解:从请求原理到错误码排查的实战指南

curl命令行详解:从请求原理到错误码排查的实战指南 如果你经常跟服务器打交道恐怕没有哪一天能完全避开 curl。哪怕只是登录服务器敲两行命令或者写个脚本去调一下接口curl 总是那个甩不掉又最省事的家伙。它就是一个命令行下的网络请求工具支持 HTTP、HTTPS、FTP 等几十种协议能把 GET、POST、PUT、DELETE 这些请求原封不动地发出去也能把服务器返回的内容老老实实地拉回来存成本地文件。这些年我用 curl 的频率远高于任何图形化接口调试工具原因很简单任何一台 Linux 机器、macOS 都自带 curlWindows 10 之后也内置了。只要你能敲命令行就能用 curl 完成接口联调、文件下载、健康检查、数据抓取这些工作。这篇文章我尽量把日常最能派上用场的命令、参数、报错排查经验一次讲清楚适合刚接触命令行的新手也能帮老手省掉翻文档的时间。1. curl到底是什么核心概念与原理解析1.1 一个命令行“快递员”的自我修养先说个类比。你在浏览器里输入网址浏览器会帮你把请求发出去再把网页画出来而 curl 干的是同一件事只是它不做页面渲染只把服务器返回的原始内容打到终端上。你可以把 curl 理解为一个“命令行快递员”你告诉它快递单号URL它负责把请求包裹送到目的地再把服务器的回执和货品原样拿回来。curl 的历史可以追溯到 1997 年最初只是作者 Daniel Stenberg 写的一个下载 FTP 文件的小工具后来一路扩展成支持 HTTP、HTTPS、FTP、SFTP、SMTP、IMAP 这些主流协议的网络瑞士军刀。说它是“随系统自带的第一调试工具”一点不夸张很多没有图形界面的服务器环境里排查问题时第一个想到的就是 curl。在开始前可以在终端里先跑一下curl --version你会看到当前版本号以及编译时支持的协议列表。不同发行版自带的 curl 版本可能不同但常用参数基本都稳定了几十年不用太纠结版本差异。1.2 curl处理一个请求的完整流程搞懂 curl 的底层流程对你排查报错会有很大帮助。执行一条简单的curl http://example.com实际经历了这几个阶段URL 解析curl 先分析你给的地址确定协议类型http://、https://、ftp:// 等、主机名、端口、路径。DNS 解析把主机名翻译成 IP 地址。这一步相当于“查通讯录”如果查不到就会报错误码 6。TCP 三次握手与目标服务器建立可靠的传输连接。TLS/SSL 握手如果地址是 https:// 开头还会进行加密协商和证书校验这一步出事就会报错误码 35 或 60。发送 HTTP 请求把请求行、请求头、请求体按协议格式发给服务器。接收响应等待服务器返回响应头和响应体然后原样输出到终端。连接关闭请求结束后按 Keep-Alive 策略关闭或复用连接。理解这个顺序后你会发现curl 报错其实是在告诉你“卡在了哪一步”6 是 DNS 挂了7 是 TCP 连不上35/60 是 TLS 握手失败22 是 HTTP 层被拒。后面第 4 章我会完整展开这些错误码的排查方法这里先留个印象。2. 高频命令第一梯队日常开发最常用的参数组合2.1 最简单的GET与“照着抄”的POST写法最基本的用法就是一个 URL 打到底curl https://www.example.com不加任何参数时curl 默认发送 GET 请求并把响应体打印到终端。但是真实开发场景里POST 请求才是重头戏尤其是 JSON 接口的联调。我经常看到有人把 POST 写得很啰嗦其实核心只需要两点指定请求头里的Content-Type以及用-d传请求体。curl -X POST https://api.example.com/login \ -H Content-Type: application/json \ -d {username:admin,password:123456}这里有个细节容易踩坑-d默认会把请求方法从 GET 改成 POST所以理论上不加-X POST也能工作。但当你遇到特殊情况比如要发一个带请求体的 GET 请求或者想用-X PUT覆盖默认动作时-X就派上用场了。我的习惯是常规 POST 不写-X让-d自己决定特殊方法如 PUT、DELETE 再用-X明确指定避免命令行上发生行为冲突。如果接口接收的是普通表单格式写法更简单curl -X POST https://api.example.com/form \ -d namezhangsanage18-d会自动设置Content-Type: application/x-www-form-urlencoded所以不需要手动加请求头。2.2 请求头、Cookie与会话保持的实战组合很多接口需要带鉴权信息或模拟登录态。带请求头用的是-H可以重复出现多次curl https://api.example.com/user \ -H Authorization: Bearer your_token_here \ -H Accept: application/json如果你想模拟浏览器访问可以指定-A自定义 User-Agent想直接带一个 Cookie 头用-b namevalue。但更常用的场景是两步登录先请求登录接口让服务器下发会话 Cookie再带着这个 Cookie 请求业务接口。第一步登录并把返回的 Cookie 保存在本地文件curl -c cookies.txt -X POST https://api.example.com/login \ -H Content-Type: application/json \ -d {username:admin,password:123456}第二步后续请求带上这个 Cookie 文件curl -b cookies.txt https://api.example.com/profile-c是“写入 Cookie 到文件”-b是“从文件读取 Cookie”这两个参数配合起来可以很轻松地在命令行里模拟一个完整的登录会话流程。很多内部系统的接口联调我就是靠这一招几天都不用重新登录。2.3 用 -w 输出状态码与请求耗时日常调试时光看到响应体还不够我经常还需要确认 HTTP 状态码、DNS 耗时、总耗时这些信息。curl 的-w参数可以把这些变量打印出来配合-o把响应体丢弃只保留统计信息是写脚本时的黄金组合curl -s -o /dev/null -w HTTP状态码: %{http_code}\n总耗时: %{time_total}s\n https://www.example.com-o /dev/null的意思是响应体不写入文件也不打到终端Linux 下/dev/null就是个黑洞-w后面的字符串里可以嵌入 curl 支持的各种变量。常用的几个我整理在下面变量含义典型使用场景%{http_code}HTTP 响应状态码如 200、404判断接口是否成功%{time_total}从开始到结束的总耗时秒评估接口性能%{time_connect}TCP 建连耗时秒排查网络延迟%{time_starttransfer}从开始到收到第一个字节的耗时秒看服务端处理速度%{size_download}下载的字节数确认响应大小%{url_effective}最终请求的 URL检查重定向结果用-w配合-o /dev/null后你在脚本里就可以轻松写“如果状态码不是 200 就报警”这种逻辑了。说实话我写的不少定时监控脚本底层就是这一条命令再加一个 if 判断。3. 进阶场景下载、断点续传、SSE与调试输出3.1 文件下载与上传的正确姿势下载文件是 curl 的看家本领。最简单的是用-o指定保存文件名curl -o linux.tar.gz https://mirrors.example.com/linux.tar.gz如果想要自动用远程文件名保存就换成大写-Ocurl -O https://mirrors.example.com/file.zip实际运维中你经常会看到类似这样的命令curl -o /etc/yum.repos.d/centos-base.repo https://mirrors.aliyun.com/repo/Centos-7.repo这就是利用-o把远程仓库配置文件直接写入指定目录避免了先下载再手动移动的两步操作。同理下载安装包、备份文件、拉取脚本配置时-o都是最常用的选项。如果下载一半断了想续传怎么办加-C -curl 会自动检测本地已有文件大小从断点处继续下载curl -C - -O https://mirrors.example.com/bigfile.zip这个参数我强烈建议记下来下载大文件时遇到断网能省下从头再来的时间。上传文件则用-F模拟表单的 multipart 格式curl -X POST https://upload.example.com/upload \ -F file./report.pdf-F的语法是字段名本地文件路径服务端按普通表单文件字段接收即可。我常用它来快速往测试服务器传日志包比开 SFTP 工具还快。3.2 SSE流式响应curl能不能吃很多人不知道 curl 也能处理 SSEServer-Sent Events这种流式响应。SSE 是服务器主动向客户端持续推送消息的技术典型场景是 AI 聊天、实时通知、日志流。用 curl 调试 SSE 接口时关键参数是-Ncurl -N https://api.example.com/events-N的全称是--no-buffer作用是关闭 curl 的输出缓冲。这里解释一下为什么默认要缓冲当 curl 的 stdout 不是终端而是管道或文件时它会把收到的数据攒到一定量再输出避免频繁写磁盘的开销但这对于实时流式的场景就致命了数据会积压在你眼前半天刷不出来。加上-N后每条服务器推送到达时都会立即打印出来调试 SSE 接口体验好了不止一个档次。如果担心流式接口挂住不退出可以配合--max-time设定一个观察窗口curl -N --max-time 30 https://api.example.com/events这样 curl 最多运行 30 秒就自动结束非常适合脚本里做短时探测。3.3 调试三板斧-v、-i、-s排查接口问题时我的第一步永远是加-v。它会完整打印请求行、请求头、TLS 握手信息、响应头最后才是响应体curl -v https://api.example.com/login输出里带的表示发出的请求内容带的表示收到的响应内容。你能看到实际发给了服务器什么数据这是定位“为什么接口说参数缺失”最直接的手段。只想看响应头的话用-i就能把响应头和响应体一起打印出来比-v清爽一些。脚本里如果不想看到进度条和额外信息加-s进入静默模式它只输出响应体本身。但要注意-s会把错误信息也吞掉所以我一般用-sS组合静默但保留错误提示排查问题时不会一头雾水。curl -sS -o /dev/null -w %{http_code}\n https://api.example.com/health调试思路可以总结成一句话先用-v看细节再用-i看响应头最后用-sS保持输出干净。三个阶段逐步收紧问题基本都能定位。4. 常见错误码排查手册从35到60再到7的避坑实录4.1 连接层故障怎么定位错误码6和7错误码 6 的完整提示是Could not resolve host意思是 DNS 解析失败。域名拼错了或者本机 DNS 配置有问题都会触发它。排查思路很简单先检查域名拼写再ping 域名或nslookup 域名手动验证解析是否正常。如果解析正常但 curl 依然报 6那就要查看/etc/resolv.conf里的 DNS 服务器配置了。错误码 7 的出现频率更高提示是Failed to connect to host。TCP 层连不上。可能的原因很多端口没开、服务没启动、防火墙拦截、IP 地址不通。我排查时按顺序走四步确认端口是否监听ss -lntp | grep 8080或netstat -lntp确认服务状态systemctl status 服务名确认防火墙规则iptables -L -n或firewall-cmd --list-all用telnet 目标IP 端口或nc -vz 目标IP 端口直测端口连通性有一个经常被忽略的因素是环境变量代理。公司内网机器经常会在系统里设置http_proxy和https_proxy某些软件安装时会改动这些变量。之后的 curl 请求都走了代理而代理本身又连不上目标地址就会出现“本机明明能访问curl 却报 7”的诡异现象。排查时可以临时清掉这些变量再试unset http_proxy https_proxy curl -v https://example.com这个坑我踩过好几次强烈建议所有遇到连接失败的人先做这一步。4.2 TLS以及SSL证书问题错误码35与60的组合拳如果说错误码 7 是“连不上”那错误码 35 和 60 就是“连上了但不敢确认对方身份”。这两个是日常开发里最常见的 HTTPS 报错。错误码 60证书验证失败。提示一般是SSL certificate problem: unable to get local issuer certificate或certificate has expired。产生原因是服务器使用的 SSL 证书未通过 curl 内置 CA 证书库的校验——自签名证书、内网私有 CA 颁发的证书、证书链不完整、证书过期都会触发 60。遇到 60 时按安全性从高到低有三种解法方案命令/操作适用场景将证书加入系统信任库将 cer/crt 文件复制到/etc/pki/ca-trust/source/anchors/执行update-ca-trust公司内部服务希望长期信任指定 CA 文件校验curl --cacert /path/to/ca.crt URL临时验证某个私有证书跳过证书校验curl -k URL仅限本地测试不推荐生产-k是最后的手段它等于告诉 curl “不管你是谁我都信你”。这个参数对排查问题很快但一旦用于生产环境等于把 HTTPS 的加密保护完全放弃中间人攻击风险极高。我自己的原则是-k只出现在本地调试的临时命令里任何写进脚本的命令都尽量走证书信任方案。错误码 35TLS/SSL 连接错误。提示五花八门Windows 上常见的有一句curl: (35) schannel: next InitializeSecurityContext failed: CRYPT_E_REVOCATION这个报错说的是 Windows 自带的 Schannel 在检查服务器证书是否被吊销时无法完成吊销状态查询。说白了就是系统想要确认这张证书有没有被提前作废但查询不到吊销服务器。解决办法是在 curl 命令里加上--ssl-no-revoke跳过吊销检查curl --ssl-no-revoke https://example.com如果是 Linux 上出现 35常见原因则是 TLS 版本不兼容。老服务端不支持新 TLS 协议时可以用--tlsv1.2或--tlsv1.1强制指定版本。还有一个经常被忽略的因素系统时间不对。TLS 握手时客户端要校验证书有效期如果本机时间差了好几年证书校验必然失败。遇到 TLS 相关报错第一件事看一下date输出。4.3 超时与HTTP响应类的区分错误码22和28错误码 22 的提示是HTTP page not retrieved。它和前面几种错误本质不同——连接、TLS 全部正常请求也发出去了但服务器返回的 HTTP 状态码不是 2xx/3xx 范围内的“正常码”。简单说就是服务端“给了个面子但拒绝了内容”。要看到具体状态码配合-w就行curl -sS -o /dev/null -w %{http_code}\n https://api.example.com比如得到 404 是路径不对得到 500 是服务端程序崩了得到 401/403 是鉴权失败。错误码 22 只是个笼统的结果真正要解决的是那个具体的 HTTP 状态码背后的业务问题。错误码 28 是Operation timeout。curl 默认不设超时如果对方一直不响应它会一直等下去这在脚本里非常危险。所以写脚本时要养成分开设置两个超时的习惯--connect-timeout控制 TCP 连接建立的超时--max-time控制整个请求的总超时。curl --connect-timeout 5 --max-time 30 https://api.example.com前者能快速失败不会因为端口不通等半天后者能兜底防止响应体太大拖死脚本。建议所有自动化脚本里的 curl 都加上这两个参数代价极低但收益巨大。4.4 两个真实报错的排查全过程整理错误码时我特意把网上高频出现的两个案例拿出来完整走一遍排查流程因为它们的典型性值得借鉴。案例一访问内网系统报 60你可能会看到这样的报错curl https://esign.cqipu.edu.cn:9100/ curl: (60) SSL certificate problem: self signed certificate这通常是学校、企业内部系统的常见问题用自签名证书开启的 HTTPS 服务curl 不认。我在排查时是这样处理的先不带-k看完整错误信息确认到底是self signed certificate还是unable to get local issuer certificate这能帮助判断证书是自签名还是证书链缺失。然后把这个地址在浏览器里打开点击地址栏的小锁图标把证书导出为.cer或.crt文件。最后把这个文件放入系统的 CA 信任目录并更新。对于 Ubuntu/Debian 系统sudo cp mycert.crt /usr/local/share/ca-certificates/ sudo update-ca-certificates对于 CentOS/RHEL 系列sudo cp mycert.crt /etc/pki/ca-trust/source/anchors/ sudo update-ca-trust之后 curl 访问这个地址就不会再报 60。整个过程不需要-k安全且一劳永逸。案例二报 35 且提示 TCP connection reset by peer这个报错原文是curl: (35) TCP connection reset by peer意思是 TLS 握手过程中服务器把 TCP 连接直接重置了。常见原因有两个一是 TLS 版本不兼容比如服务器只支持 TLS 1.0而你机器上的 curl 默认尝试 TLS 1.3二是某些安全软件或防火墙策略主动重置了不支持加密套件的连接。排查时我先尝试锁定 TLS 版本curl --tlsv1.2 -v https://example.com如果不行再换--tlsv1.1甚至--tlsv1.0。如果版本怎么试都不行再排查防火墙、安全组策略或者换一台网络环境验证。这类问题在网络隔离严格的企业内网中尤其常见换个网络往往就好了。5. 提升效率的联动玩法脚本、Postman与日常命令行5.1 安装脚本里的那条“curl管道命令”是什么原理现在很多开发工具、运行环境的官方安装文档里都会给出一行类似这样的命令curl -fsSL https://example.com/install.sh | sh很多新手第一次看到时是懵的。拆开来看curl负责把远程脚本内容下载到标准输出管道符|把输出转交给sh来执行。这里的几个参数也各有讲究-f遇到 HTTP 错误时直接失败退出避免把 404 页面当脚本执行。-s静默模式不显示进度条。-S与-s一起用保留真正的错误提示。-L自动跟随重定向很多下载地址会先跳转一次。所以-fsSL合起来的意思是“静默下载但保留错误提示跟随重定向下载失败绝不硬执行”。这套参数对官方脚本是安全的但我要提醒一句先下载到本地看一眼再执行永远是更稳妥的做法。尤其是从非官方网站拉脚本时至少先执行curl -fsSL -o install.sh https://example.com/install.sh # 然后用 vim/less 查看 install.sh 内容确认没有危险操作后再执行 bash install.sh命令行管道虽然方便但“下载即执行”意味着你完全信任了远端脚本的内容。多看一步能避免很多安全风险。5.2 Postman一键导出curl命令团队协作时最常遇到的场景是同事在 Postman 里调通了接口但到了命令行环境却不知道该怎么复现。这时候 Postman 的“导出 curl”功能就非常实用。具体步骤是在 Postman 中构造好请求点击Send确认能正常返回。点击请求面板右侧的/代码图标。在弹出窗口左侧语言列表中选择cURL。点击Copy to Clipboard复制整条 curl 命令。粘贴到终端后你就能直接得到一条完整的 curl 命令curl --location https://api.example.com/login \ --header Content-Type: application/json \ --data-raw {username:admin,password:123456}注意 Postman 导出的命令里常带--location等价于-L以及多个--header其中有些是 Postman 自动加上的模拟浏览器请求头在命令行调试时删掉也无所谓。我一般会把它精简成-H和-d两部分可读性更好。这个技巧在给同事复现问题、写 Bug 报告时简直太方便了直接丢一条命令过去比截图和文字描述省事得多。5.3 curl与jq、grep、vim的组合拳curl 本身只负责“收发数据”要让它融入日常命令行工作流还需要几个搭档。第一个搭档是jq专门用来解析 JSON 响应。直接把 curl 的输出管道给 jq格式化和提取字段一步到位curl -s https://api.example.com/user | jq .name第二个搭档是grep适合从 HTML 或纯文本响应里过滤关键词curl -s https://www.example.com | grep -i title第三个搭档是vim。当接口返回的是一大段 JSON 或 HTML直接在终端里看很难受时我会把响应保存到临时文件再用 vim 查看curl -s https://api.example.com/data /tmp/response.json vim /tmp/response.json最后分享一个我每天都在用的封装思路在 shell 配置里比如~/.bashrc或~/.zshrc写一个简易函数把超时、静默、状态码输出这些常用参数组合起来避免每次敲一长串参数mycurl() { curl --connect-timeout 5 --max-time 30 -sS \ -w \n HTTP状态码: %{http_code} \n $ }保存后用source ~/.bashrc生效后面的所有 curl 调用都用mycurl替代脚本里处理异常就轻松多了。我在实际工作中还经常用 curl 做一件事写一个几行的巡检脚本对多个服务的健康检查接口做轮询状态码非 200 就输出告警。核心逻辑就是这一章讲的-w、--connect-timeout、--max-time的组合。说实话很多东西都是从第一条 curl 命令开始长出来的你把它用熟了后面一整条自动化链路都会顺畅起来。
返回列表