尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
curl GET与POST请求实战:JSON参数、编码与调试技巧
1. 为什么值得花时间把curl的GET和POST彻底搞明白日常开发里调试接口这件事几乎每天都在发生。浏览器里点来点去只能覆盖最简单的场景一旦遇到需要自定义请求头、携带JSON体、模拟特定认证方式的情况图形化工具就开始捉襟见肘。而curl这个命令行工具几乎每一台开发机、每一台服务器上都预装着不需要额外安装不需要打开任何界面一条命令就能把请求发出去结果直接打印在终端里。这种“随手可用”的特性让它在接口调试、自动化脚本、CI/CD流水线里成了不可替代的存在。这篇文章要聊的就是curl最核心的两个用法发送带JSON参数的POST请求和发送GET请求。看起来简单但实际操作中踩坑的人非常多——JSON引号被shell吃掉、中文乱码、Content-Type没设对导致服务端解析失败、GET请求参数里的特殊字符没有转义、重定向和超时行为不符合预期这些问题几乎每个后端或前端开发者都遇到过至少一次。我会从实际使用的角度把这两个请求方式的完整细节拆开讲清楚包括参数怎么传、请求头怎么设、常见错误怎么排查以及一些在脚本里批量调用接口时的实用技巧。不管你是刚接触接口调试的新手还是已经用了几年curl但一直靠“复制粘贴改改”过日子的老手下面这些内容都值得过一遍。因为很多问题的根源不是curl本身难用而是shell的解析规则和HTTP协议的细节在背后“捣鬼”搞清楚这些你才能真正做到“一条命令解决问题”而不是反复试错。2. curl发送GET请求的完整拆解2.1 GET请求的基本形态与最简用法GET请求是HTTP协议里最基础的方法语义是“获取资源”。用curl发一个GET请求最简单的形式就是直接把URL跟在命令后面curl https://api.example.com/users这条命令执行后curl会向目标地址发起一个GET请求然后把服务端返回的响应体直接打印到终端。默认情况下curl不会显示响应头也不会显示请求过程只输出body内容。如果你在终端里看到了一串JSON或者HTML说明请求成功了。但这里有个很多人忽略的点curl默认会把响应体直接输出到标准输出如果你请求的是一个二进制文件比如图片终端会显示一堆乱码。这时候需要用-o参数把结果写到文件里curl -o response.json https://api.example.com/users或者用-O参数让curl自动以URL的最后一段作为文件名保存curl -O https://api.example.com/files/report.pdf这两个参数的区别很实用-o是你自己指定文件名-O是让curl根据URL自动命名。下载文件的时候用-O省事但URL里带查询参数时自动命名可能会出问题这时候还是老老实实用-o。2.2 带查询参数的GET请求怎么写才不出错GET请求传参数的方式是拼在URL后面的查询字符串query string格式是?key1value1key2value2。很多人第一次写的时候会直接这样curl https://api.example.com/search?keywordhello worldpage1这条命令在终端里执行会出问题。原因在于shell会把空格当作参数分隔符hello和world被拆成了两个部分curl实际收到的URL是https://api.example.com/search?keywordhello后面的worldpage1被当成了额外的参数。正确的做法是用引号把整个URL包起来curl https://api.example.com/search?keywordhello worldpage1但即使加了引号空格在URL里也是不合法的字符服务端收到后可能会解析异常。更规范的做法是对参数值做URL编码空格编码成%20curl https://api.example.com/search?keywordhello%20worldpage1curl本身提供了一个--data-urlencode参数但它主要用于POST请求。对于GET请求如果你不想手动编码可以用-G参数配合--data-urlencode来实现自动编码curl -G https://api.example.com/search --data-urlencode keywordhello world --data-urlencode page1这条命令里-G告诉curl“把后面用--data-urlencode指定的数据作为查询参数拼到URL上而不是放在请求体里”。curl会自动把hello world编码成hello%20world最终发出的URL是https://api.example.com/search?keywordhello%20worldpage1。这个用法在参数值包含中文、空格、特殊符号时特别省心强烈建议记住。提示中文参数一定要编码。虽然很多服务端框架能自动处理未编码的中文但HTTP协议层面URL只允许ASCII字符不编码在某些代理或网关环节会直接报400错误。2.3 GET请求中查看响应头和调试信息默认情况下curl只输出响应体但调试接口时经常需要看响应头比如检查Content-Type、Set-Cookie、Cache-Control这些字段。用-i参数可以把响应头和响应体一起输出curl -i https://api.example.com/users如果只想看响应头不关心body用-I参数发送一个HEAD请求curl -I https://api.example.com/users注意-I发送的是HEAD方法不是GET。有些服务端对HEAD方法的支持不完整可能返回405或者不返回正确的头信息。如果你需要发送GET请求但只看响应头可以用-i配合-o /dev/null把body丢弃curl -i -o /dev/null https://api.example.com/users调试时另一个非常有用的参数是-v它会输出完整的请求和响应过程包括TCP连接、TLS握手、发送的请求头、收到的响应头curl -v https://api.example.com/users-v的输出里以开头的行是curl发送的请求内容以开头的行是服务端返回的响应内容。当你怀疑请求头没设对、认证信息没带上、或者服务端返回了非预期的状态码时-v是第一手排查工具。如果觉得-v输出还不够详细可以用--trace-ascii -把每一个字节的收发都打印出来不过这个通常只在排查极端诡异的协议问题时才用得上。2.4 GET请求的常见误区与实操心得第一个误区是忽略重定向。curl默认不跟随重定向如果服务端返回301或302curl只会把重定向的响应头打印出来不会自动跳到新地址。很多API在HTTP和HTTPS之间跳转或者带不带末尾斜杠会跳转这时候需要加-L参数curl -L https://api.example.com/users/加了-L之后curl会自动跟随Location头指向的新地址。但要注意跟随重定向时curl默认会把认证信息也带到新地址如果跨域跳转可能会有安全问题可以用--max-redirs限制跳转次数。第二个误区是不设超时。默认情况下curl会一直等待服务端响应如果服务端卡住你的脚本就会挂在那里。生产环境的脚本里一定要加超时参数curl --connect-timeout 5 --max-time 15 https://api.example.com/users--connect-timeout是连接阶段的超时--max-time是整个请求的最大耗时。两个都设上才能保证脚本不会因为一个慢接口而整体卡死。第三个误区是在循环里反复调用时不复用连接。如果你在脚本里连续请求同一个域名的多个接口每次curl都重新建立TCP连接和TLS握手开销很大。可以用--keepalive-time或者在一个curl命令里指定多个URL来复用连接curl https://api.example.com/users https://api.example.com/orders https://api.example.com/products这样curl会在同一个连接上依次请求这三个地址省去了重复握手的时间。不过要注意这种方式下每个URL的响应会依次输出如果某个请求失败后面的请求默认还是会继续执行。3. curl发送POST请求带JSON参数的实战细节3.1 POST请求的基本结构与Content-Type的重要性POST请求和GET请求最大的区别在于数据是放在请求体body里发送的而不是拼在URL上。用curl发POST请求核心参数是-X POST和-d或者--datacurl -X POST -d {name:张三,age:25} https://api.example.com/users这条命令看起来没问题但实际发给服务端后很多框架会解析失败。原因在于Content-Type。curl用-d发送数据时默认的Content-Type是application/x-www-form-urlencoded而不是application/json。服务端看到这个Content-Type会按照表单格式去解析body结果就是解析出来的字段全是乱的。正确的做法是显式指定Content-Type为application/jsoncurl -X POST -H Content-Type: application/json -d {name:张三,age:25} https://api.example.com/users加上-H Content-Type: application/json之后服务端才知道body里是JSON格式会用JSON解析器去处理。这个细节是新手最容易踩的坑没有之一。我见过太多人调试了半天以为是JSON格式写错了最后发现只是少了一个请求头。注意-H参数可以多次使用每次指定一个请求头。curl会自动把多个-H合并到请求里。请求头的名字不区分大小写但值通常区分大小写比如application/json不能写成Application/JSON。3.2 JSON参数里的引号问题与shell转义在命令行里写JSON最头疼的就是引号。JSON本身要求键和字符串值用双引号而shell里双引号又有特殊含义。上面那条命令用的是单引号包裹整个JSON这样shell不会对里面的双引号做处理是最省事的写法。但如果JSON里本身需要包含单引号比如{name:OBrien}单引号包裹就会出问题。这时候有几种处理方式。第一种是用双引号包裹然后对JSON里的双引号做转义curl -X POST -H Content-Type: application/json -d {\name\:\OBrien\} https://api.example.com/users这种写法可读性很差JSON稍微长一点就容易写错。第二种方式是把JSON写到文件里然后用-d filename读取curl -X POST -H Content-Type: application/json -d payload.json https://api.example.com/userspayload.json文件里直接写标准的JSON不需要任何转义。这是处理复杂JSON最推荐的方式尤其是在脚本里把JSON和命令分离维护起来清晰得多。第三种方式是用here-documentcurl -X POST -H Content-Type: application/json -d - https://api.example.com/users EOF { name: 张三, age: 25, tags: [developer, backend] } EOF-d -表示从标准输入读取数据here-document里的内容原样传给curl。这种方式在shell脚本里特别实用既不需要额外文件也不用担心转义问题。3.3 发送嵌套JSON和数组的注意事项实际接口里JSON往往不是简单的键值对而是嵌套对象或者数组。比如{ user: { name: 张三, contacts: { email: zhangsanexample.com, phone: 13800138000 } }, roles: [admin, editor] }这种结构用命令行直接写很容易出错因为括号和引号太多肉眼很难检查。我的建议是只要JSON超过两层嵌套就一律用文件方式发送。如果非要在命令行里写可以用python -m json.tool或者jq先验证JSON格式是否正确echo {user:{name:张三}} | python -m json.tool这条命令会把JSON格式化输出如果格式有误会直接报错。确认无误后再把同样的内容放到curl命令里。另外jq工具在构造JSON时非常方便可以用它动态生成JSON再传给curljq -n --arg name 张三 --arg email zhangsanexample.com {user:{name:$name,contacts:{email:$email}}} | curl -X POST -H Content-Type: application/json -d - https://api.example.com/users这种管道组合的写法在自动化脚本里很常见既保证了JSON的合法性又避免了手动拼接字符串的转义问题。3.4 POST请求中其他常用参数与行为控制除了-d和-HPOST请求还有几个参数值得掌握。--data-binary和-d的区别在于-d会去掉数据里的换行符而--data-binary会原样发送。如果你发送的JSON是格式化过的、带换行的用-d会把换行去掉虽然对JSON解析没影响但如果你需要计算签名或者校验原始body就必须用--data-binarycurl -X POST -H Content-Type: application/json --data-binary payload.json https://api.example.com/users--data-raw和-d类似但它不会把开头的字符串当作文件名处理。如果你的JSON值恰好以开头用-d会被curl误认为是读取文件这时候要用--data-raw。另一个常用的是-u参数用于HTTP Basic认证curl -X POST -u username:password -H Content-Type: application/json -d payload.json https://api.example.com/userscurl会自动把username:password做Base64编码放到Authorization头里。不过在生产环境里密码直接写在命令行里会留在shell历史记录中更安全的做法是用-u usernamecurl会交互式提示输入密码或者用--netrc从配置文件读取。如果服务端需要Bearer Token认证就用-H手动加Authorization头curl -X POST -H Authorization: Bearer your_token_here -H Content-Type: application/json -d payload.json https://api.example.com/usersToken同样不建议直接写在命令行里可以在脚本里从环境变量读取curl -X POST -H Authorization: Bearer $API_TOKEN -H Content-Type: application/json -d payload.json https://api.example.com/users这样Token不会出现在命令历史里也方便在不同环境之间切换。4. 高频问题排查与实战经验汇总4.1 服务端返回400/415错误时怎么快速定位400 Bad Request和415 Unsupported Media Type是POST JSON请求最常见的两个错误码。415通常意味着Content-Type没设对服务端不支持你发送的媒体类型。排查步骤很简单先用-v看curl实际发送的请求头里Content-Type是什么确认是不是application/json。如果Content-Type对了但还是415检查一下是不是多打了空格或者大小写有问题。400的原因就多了可能是JSON格式错误、缺少必填字段、字段类型不对。这时候光看curl的输出不够要把服务端返回的响应体完整打印出来。很多框架会在响应体里给出具体的错误信息比如“field name is required”或者“invalid JSON at position 15”。用-i参数把响应头和响应体一起输出或者直接不加任何参数curl默认就会输出响应体。如果服务端返回的body是空的那就需要看服务端的日志了。这种情况下用--trace-ascii -把curl发送的原始数据打印出来和服务端日志里的请求体做对比通常能发现是编码问题还是数据被截断。4.2 中文乱码和编码问题的根源分析中文乱码在curl请求里出现通常有两个原因。第一个是终端本身的编码和curl输出的编码不一致这个只影响你在终端里看到的显示不影响实际发送的数据。第二个是请求体或URL里的中文没有正确编码导致服务端解析出来的字节序列不是合法的UTF-8。对于POST JSON请求只要Content-Type里声明了charsetutf-8并且你发送的JSON文件本身是UTF-8编码一般不会有问题。但有些服务端框架要求Content-Type必须精确匹配application/json;charsetUTF-8少一个charset就会用默认编码解析。保险起见可以在Content-Type里显式加上charsetcurl -X POST -H Content-Type: application/json; charsetutf-8 -d payload.json https://api.example.com/users对于GET请求里的中文参数一定要用--data-urlencode配合-G让curl自动做URL编码。手动拼中文到URL里即使终端显示正常实际发送的字节也可能不符合HTTP规范。4.3 超时、连接失败与重试策略网络请求失败的原因很多curl返回的错误码能帮你快速定位。退出码6表示无法解析域名7表示连接被拒绝28表示超时35表示TLS握手失败。在脚本里可以根据退出码做不同的处理curl -X POST -H Content-Type: application/json -d payload.json https://api.example.com/users if [ $? -eq 28 ]; then echo 请求超时准备重试 fi对于不稳定的网络环境可以用--retry参数让curl自动重试curl --retry 3 --retry-delay 2 --retry-connrefused -X POST -H Content-Type: application/json -d payload.json https://api.example.com/users--retry 3表示最多重试3次--retry-delay 2表示每次重试间隔2秒--retry-connrefused表示连接被拒绝时也重试。注意默认情况下curl只对超时和5xx错误重试对4xx错误不重试因为4xx通常意味着请求本身有问题重试也没用。4.4 常见问题速查表问题现象可能原因排查方法解决方案服务端返回415Content-Type未设置或设置错误用-v查看请求头添加-H Content-Type: application/jsonJSON解析失败JSON格式错误或引号转义问题用python -m json.tool验证改用-d file从文件读取中文显示乱码终端编码或URL未编码检查locale和请求体编码GET用--data-urlencodePOST确保文件为UTF-8请求一直挂起未设置超时观察curl是否卡住添加--connect-timeout和--max-time重定向后请求失败未跟随重定向用-v查看是否返回301/302添加-L参数认证失败Token未正确传递用-v查看Authorization头检查-H或-u参数请求体被截断数据中包含特殊字符用--trace-ascii -查看原始数据改用--data-binary4.5 在脚本中批量调用接口的实用技巧当你需要在shell脚本里循环调用接口时有几个细节能帮你省不少事。第一把公共的请求头和URL前缀提取成变量API_BASEhttps://api.example.com AUTH_HEADERAuthorization: Bearer $API_TOKEN CONTENT_TYPEContent-Type: application/json for id in 1 2 3 4 5; do curl -s -X POST -H $AUTH_HEADER -H $CONTENT_TYPE -d {\id\:$id} $API_BASE/process done-s参数让curl静默执行不显示进度条和错误信息适合在脚本里用。如果需要看错误可以加-S让curl在静默模式下仍然显示错误信息。第二用-w参数输出请求的耗时和状态码方便做监控和统计curl -s -o /dev/null -w status%{http_code} time%{time_total}s\n -X POST -H $CONTENT_TYPE -d payload.json $API_BASE/users-w支持很多变量常用的有%{http_code}HTTP状态码、%{time_total}总耗时、%{time_connect}连接耗时、%{size_download}下载字节数。把这些输出重定向到日志文件就能对接口的稳定性和性能有一个直观的记录。第三如果脚本里需要并发调用多个接口可以用把curl放到后台执行然后用wait等待所有请求完成for id in 1 2 3 4 5; do curl -s -X POST -H $CONTENT_TYPE -d {\id\:$id} $API_BASE/process done wait echo 所有请求已完成不过并发调用时要注意服务端的承受能力以及输出可能会交错在一起。如果需要收集每个请求的结果可以把输出写到不同的临时文件里最后再合并。5. 从GET到POST把curl真正用顺手的几个习惯5.1 用配置文件管理常用参数如果你经常请求同一个API每次都敲一长串-H和URL前缀很烦。curl支持从配置文件读取默认参数配置文件默认路径是~/.curlrc你也可以用-K指定自定义配置文件curl -K api-config.txt https://api.example.com/usersapi-config.txt里可以写header Content-Type: application/json header Authorization: Bearer your_token_here connect-timeout 5 max-time 15这样每次请求都会自动带上这些参数命令行里只需要写URL和-d就行了。配置文件的方式在团队协作时也很有用可以把公共配置放在项目目录里大家共用。5.2 把curl输出格式化成可读的JSONcurl返回的JSON默认是一整行字段多了以后很难看。用jq管道格式化一下可读性立刻提升curl -s https://api.example.com/users | jq .如果jq没装用python -m json.tool也能达到类似效果curl -s https://api.example.com/users | python -m json.tool这两个工具还能用来提取特定字段比如只看返回列表里每个元素的id和namecurl -s https://api.example.com/users | jq .[] | {id, name}调试接口时这种“请求格式化提取”的组合能让你快速看清数据结构比在终端里瞪着一行超长的JSON高效得多。5.3 保存和复用请求的实战建议调试成功的curl命令建议随手保存下来。可以建一个requests.md或者api-examples.sh文件把常用的请求按接口分类记下来。记录的时候把URL、方法、请求头、请求体都写清楚最好再附上一条示例响应。下次需要调同一个接口时直接复制粘贴改参数就行不用重新回忆当时是怎么拼的。另外浏览器开发者工具里的“Copy as cURL”功能很好用可以把浏览器里发出的请求直接导出成curl命令。但要注意浏览器导出的命令里可能包含很多不必要的请求头比如User-Agent、Accept-Encoding、Cookie等复制过来后建议精简一下只保留必要的部分。特别是Cookie里面可能包含敏感信息分享命令给别人之前一定要删掉。5.4 安全使用curl的几条底线第一不要把密码和Token硬编码在命令行里。命令行会留在shell历史记录中用history命令就能看到。用环境变量或者配置文件并且确保配置文件的权限是600。第二不要对不信任的地址发送带认证信息的请求。curl的-L跟随重定向时默认会把Authorization头带到新地址如果重定向到了一个不受控的域名认证信息就泄露了。可以用--location-trusted显式控制这个行为或者用--max-redirs 0禁止重定向。第三生产环境的脚本里一定要设超时。没有超时的curl请求在服务端无响应时会一直挂着在CI/CD流水线里可能导致整个任务卡死。--connect-timeout和--max-time是最基本的保护。第四注意请求体里的敏感数据。用-d发送的JSON如果包含手机号、身份证号、密码等敏感信息在-v或--trace-ascii的输出里会明文显示。调试完成后记得清理终端输出和日志文件。我个人在实际操作中的体会是curl这个工具看似简单但真正用好需要理解shell的解析规则和HTTP协议的细节。很多人用了几年curl遇到问题还是靠“换一种写法试试”而不是从原理上定位原因。把GET和POST这两个最基础的方法彻底搞清楚把Content-Type、引号转义、URL编码、超时重试这几个关键点吃透后面遇到再复杂的请求场景比如文件上传、多部分表单、自定义认证都能举一反三。最后再分享一个小技巧如果你不确定一条curl命令最终发出的请求长什么样加一个-v参数它会把请求行、请求头、请求体部分情况下都打印出来这是排查问题最快的方式没有之一。
RELATED

相关推荐

逻辑回归核心原理与工程调参实战:从Sigmoid到正则化

逻辑回归核心原理与工程调参实战:从Sigmoid到正则化

直接开写。逻辑回归这个名字,在我刚接触机器学习那会儿就老觉得别扭。明明是做分类的,结果名字里带着“回归”两个字,第一次听课的时候我甚至以为它跟线性回归是同一个东西。后来真正在项目里用了几次,才理解这个名字背后其实特别…

📅 2026/10/20 20:41:16
地震波偏移成像MATLAB实战:从原理、算法到定量评估

地震波偏移成像MATLAB实战:从原理、算法到定量评估

简介:本资源是一套基于MATLAB实现地震波偏移成像的完整算法代码包,面向地球物理勘探方向的研究生、科研人员及高年级本科生,聚焦解决地震图像位置失真问题,提升地下构造成像精度。包内共24个.m文件,涵盖傅里叶域F-K偏移…

📅 2026/10/20 20:36:14
Matlab朴素贝叶斯实现:从离散化到误判归因的工程闭环

Matlab朴素贝叶斯实现:从离散化到误判归因的工程闭环

简介:这是一份面向机器学习初学者与Matlab编程实践者的朴素贝叶斯分类器教学实现资源,聚焦算法原理落地与代码级理解。压缩包共3个文件,全部为.m脚本(nbv_predict.m、nbc_train.m、test.m),分别承担预测、训…

📅 2026/10/20 20:36:14
MORE NEWS

更多资讯

📰

嵌入法特征选择实战:L1正则与树模型重要性评估全解析

做特征工程这些年,我慢慢发现一个很有意思的现象:特征选择这件事,新手总爱先跑一遍相关性矩阵,老手则更愿意把筛选逻辑直接丢给模型本身。前者是过滤法思维,后者就是今天要聊的嵌入法(Embed)。嵌…

📰

大模型失败类型驱动的干预决策:harness与weight层选择指南

1. 项目概述:当模型“说错话”时,该动代码还是动参数?最近在复现几篇大模型对齐方向的论文时,遇到一个特别有意思的问题:某次测试中,模型在回答“如何安全断开汽车电瓶负极”时,居然建议“先用金…

📰

Context-Mode设计与实现:上下文识别、模式切换与状态隔离

1. 从“上下文模式”说起:一个被低估的工程概念第一次看到“context-mode”这个词,很多人会下意识觉得它是个抽象到没法落地的概念。我一开始也这么想。但真正在几个项目里被上下文切换的问题折磨过之后,才发现这个词背后藏着一类非常具体的工…

📰

UNet图像分割实战:数据预处理、跳跃连接对齐与后处理全链路

简介:本资源是一份面向Python图像处理初学者与深度学习入门者的U-Net图像分割实践项目,聚焦生物医学、遥感及卫星影像等场景下的像素级分割任务。资源提供完整可运行代码框架与配套示例数据,涵盖数据预处理、U-Net模型构建(含跳跃…

📰

技能习得底层逻辑:从知识到肌肉记忆的刻意练习路径

1. 从“skills”这个标题说起:一个被严重低估的硬核话题“skills”这个词,单独拎出来看,信息量几乎为零。它不像“分布式锁”“图像分割”“家庭收纳”那样自带场景,也不像“副业”“跳槽”那样自带情绪。但恰恰是这种极简的标题&…

📰

上下文窗口优化实战:从Token预算到动态记忆管理

做提示工程这几年,被问得最多的一个问题不是“怎么写提示词”,而是“为什么同样的玩法,有时候效果爆炸,有时候直接翻车”。我复盘过很多翻车现场,最后都指向同一个源头——上下文窗口没管好。上下文窗口优化&#xff0…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬