ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

curl 发送 JSON 格式 POST 请求:参数、转义与排查实践

curl 发送 JSON 格式 POST 请求:参数、转义与排查实践

1. 每次对接新接口,我第一反应还是打开终端敲 curl

干这行时间久了,工具换来换去,但 curl 始终留在最顺手的位置。不管是照着文档试一个新接口、复现线上返回的异常、还是给同事演示"这个请求到底发了什么",一条curl命令甩过去,比截图、比导出集合文件、比录屏都直接。而这两年绝大多数接口收的都是 JSON 格式的请求体,于是如何使用 curl 命令发送 json 格式请求体的 post 请求这件事,几乎成了每天都要重复的动作——哪怕你已经敲过几百遍,隔一段时间不写,还是会回去翻自己以前的笔记。

问题就在这儿。这条命令看着只有三四个参数,但我在带新人的时候发现,能一次敲对、并且说清楚每个参数为什么这么写的人并不多。十个里有六七个会在引号、Content-Type、转义这些地方栽跟头,报错还都长得差不多,不是 400 就是 415,要么就是"参数解析失败",然后就开始怀疑服务端。实际上九成的问题出在命令行本身,请求根本没按你以为的样子发出去。

这篇东西我想把这条命令彻底拆开讲:一次 POST 请求由哪几块拼成,每个参数省掉会怎样,请求体变长以后怎么改成文件,出了错从哪一步开始查,Windows 和类 Unix 系统下的引号差异怎么处理。不管你是刚接触接口调试的在校同学,还是天天跟网关打交道的后端,都能直接拿去用。

1.1 一条命令背后其实只有四块积木

很多人学 curl 是"抄一条能跑的命令,改改 URL 和参数",这样能应付一时,但环境一换就废。真正要理解的是这四块积木:

方法(method)—— 告诉服务端你要做什么,POST 表示提交数据。地址(URL)—— 协议、域名、端口、路径、查询串。请求头(header)—— 描述请求体的格式、身份凭证、期望的响应形态。请求体(body)—— 真正承载数据的那一段 JSON 文本。

这四块里,前三块是"信封",最后一块是"信纸"。curl 的坑几乎全在"信封和信纸对不上"这件事上:你明明写了 JSON,但没告诉服务端这是 JSON,服务端就按表单去解析,解析不出来,回你一个 400 或者 415。或者你在信封上写了 JSON,但信纸被 shell 的引号规则啃掉了一个大括号,服务端收到的是残缺内容,同样报错。

所以后面所有章节,本质上都是在解决一个问题:让 curl 原封不动地把你想发的字节送到服务端,并且在信封上写清楚它是什么。

1.2 图形工具那么好用,为什么还留着命令行

有人会问,现在接口调试工具有的是,可视化、能存集合、能生成代码,为什么还要折腾命令行。我的理由是三条。

第一条是可复现。命令行是一段纯文本,可以贴进工单、贴进文档、贴进代码注释,别人复制粘贴就能跑出一样的结果。图形工具的截图做不到这一点,配置导出也常有版本兼容问题。

第二条是够近。图形工具帮你把很多细节藏起来了,藏起来的东西恰恰是出问题时最需要看的。命令行里每个头都是你自己写的,出问题时你心里清楚自己写了什么,排查路径短得多。

第三条是能进脚本。一旦某个请求需要重复跑、需要批量跑、需要挂在定时任务里跑,命令行天然就是脚本的一部分。图形工具到这一步就得靠导出代码,绕一圈又回到命令行。

当然命令行也有代价:引号、转义、换行、编码,这些在图形界面里被自动处理掉的东西,在命令行里全得你自己负责。这就是接下来要重点讲的部分。

1.3 新手最容易在第一步埋下的三个雷

在展开细节之前,我先把最常见的三个雷点摆出来,你可以对照着看自己有没有中招。

雷点一:只写了-d,没写Content-Type。curl 在只给-d的情况下,默认把请求头设成application/x-www-form-urlencoded。这是个表单格式,服务端的 JSON 解析器看到这个类型,要么直接拒绝(415),要么尝试按表单读,读出来是空。这个雷的迷惑性在于,命令能跑通、有响应,只是响应内容是错的。

雷点二:以为单引号在所有系统上都一样。在 bash、zsh 里,单引号里的内容原样保留,是写 JSON 最省心的方式。但 Windows 的 cmd 不认单引号,PowerShell 对单双引号的处理又是另一套逻辑。同一条命令从文档里复制到 Windows 终端,大概率直接报语法错误。

雷点三:JSON 里的双引号和外层引号打架。用双引号包 JSON 时,里面每个"都要转义成\",漏一个就整段结构断裂。这类错误往往不会立刻报出来,而是变成"字段对不上""值是空的"这种更绕的问题。

提示:如果你只想记住一句话,那就是——外层优先用单引号,里面放心写双引号;实在要用双引号,就把内层双引号全部转义,或者干脆把 JSON 写进文件。

2. 最小可用命令:四个参数逐个拆开讲

先把最短能跑的那条命令摆出来。假设要往某个示例服务提交一条订单,路径是/v1/orders:

curl -X POST 'https://api.example.com/v1/orders' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -d '{"sku":"A-1001","qty":2,"note":"加急"}'

这条命令里出现了-X、-H、-d三类参数,加上 URL。看着简单,但每个都有讲究,下面挨个说。

2.1-X POST到底要不要写

先说结论:带了-d(或--data、--data-binary、--json)的时候,-X POST可以省略,curl 会自动把方法设成 POST。因为-d的语义就是"提交一段数据",默认动词自然是 POST。

那为什么很多文档还是写上了?两个原因。一是显式声明可读性好,别人一眼能看出这是个 POST;二是在某些组合场景下确实需要它,比如你用-d传数据但希望方法是 PUT 或者 PATCH:

curl -X PUT 'https://api.example.com/v1/orders/1001' \ -H 'Content-Type: application/json' \ -d '{"qty":3}'

这种情况如果不写-X PUT,curl 会按 POST 发出去,服务端路由匹配不上,回你 405。所以我的习惯是:默认方法就用 POST 时省略-X,非 POST 时一定写清楚。另外提醒一句,有些老教程里会写-XPOST(不带空格),这种写法也能用,但和后面的参数连在一起时容易看错,建议还是分开写。

还有一个容易踩的点:如果你用-G把数据拼到查询串上,curl 会把方法改回 GET。这时候再叠加-X POST,就会出现"方法说是 POST,数据却在 URL 里"的怪状态,服务端可能两边都读,也可能都不读。这种组合除非你明确知道自己在干什么,否则别这么写。

2.2Content-Type漏掉的后果比你想的严重

-H 'Content-Type: application/json'是整条命令里最不能省的一行。原因前面提过:curl 在没有指定内容类型时,默认按application/x-www-form-urlencoded处理-d带的数据。

这会导致什么?举两个真实场景。第一种,服务端用的是严格的 JSON 解析中间件,看到内容类型不是 JSON,直接返回 415 Unsupported Media Type,连业务逻辑都不进。第二种,服务端用的是"宽松解析"——不管什么类型都尝试读 body 再反序列化,这种看起来能成功,但一旦它先走了表单解析器,你传的{"a":1}会被当成一个键名为{"a":1}、值为空的东西,字段全部丢失,最后报的是"缺少必填参数",让人误以为是参数名写错了。

还有一个细节:大小写和空格。Content-Type: application/json这个头名大小写不敏感,但冒号后面的空格是建议保留的。写成Content-Type:application/json(没有空格)某些严格的解析器会认,某些会出问题。另外,如果你需要指定字符集,写成application/json; charset=utf-8更保险,尤其是请求体里带中文的时候。

顺带说一句Accept头。它不是必须的,但建议加上-H 'Accept: application/json'。服务端有时会根据Accept决定返回 JSON 还是 HTML 错误页,加上它,返回的内容更好解析。

2.3-d、--data-raw、--data-binary、--json怎么选

这几个参数长得像,行为差别不小,选错了会出隐蔽的 bug。

-d也就是--data,它会把内容里的换行符去掉,多个-d之间用&连接。这个"去换行"的特性在传 JSON 时通常没影响,因为压缩成一行照样是合法 JSON。但如果你传的是需要保留格式的内容,比如带换行的文本字段,就会出问题。

--data-raw和-d行为基本一致,区别在于它不把开头的@当作"读文件"的标记。也就是说,如果你的 JSON 内容恰好以@开头(很少见),用--data-raw才不会误读文件。

--data-binary是最"老实"的一个:原样发送,不做任何换行处理。需要从文件读请求体时,我基本都用它,因为能保证字节级一致,调试签名、计算哈希这类场景全靠它。

--json是较新版本 curl 提供的语法糖,一次搞定三件事:把请求体设成你给的内容、自动加Content-Type: application/json、自动加Accept: application/json,同时隐含 POST。如果你的 curl 版本够新(7.82.0 之后),用它确实省事:

curl --json '{"sku":"A-1001","qty":2}' 'https://api.example.com/v1/orders'

但要注意,--json在旧版本上不存在,团队协作时如果同事的环境版本较低,命令会直接报"unknown option"。所以我对外分享的命令,默认还是写完整的-H加-d,兼容性最好。

参数换行处理@开头含义典型场景
-d/--data去掉换行读文件短小内联 JSON
--data-raw去掉换行当普通字符内容以@开头
--data-binary原样保留读文件从文件读、需字节一致
--json原样保留读文件新版 curl,图省事

2.4 三层引号:单引号、双引号、转义符

这是新手翻车率最高的地方,值得单独拆开讲。

单引号('...'):在 bash、zsh、sh 里,单引号内的所有字符原样保留,变量不展开、反斜杠不转义。写 JSON 最舒服,因为 JSON 本身大量使用双引号,套在单引号里完全不用管。

双引号("..."):里面的$、反引号、反斜杠会被 shell 处理。所以双引号包 JSON 时,内层的双引号必须写成\",否则 shell 会认为字符串提前结束了:

curl -X POST 'https://api.example.com/v1/orders' \ -H 'Content-Type: application/json' \ -d "{\"sku\":\"A-1001\",\"qty\":2}"

这条命令能用,但可读性差,改一个字段就要数半天引号。

单引号里要写单引号怎么办?JSON 里用不到单引号,但如果你的内容里有撇号或者 SQL 片段,就得用'\''这种拼接写法:先闭合单引号,写一个转义的单引号,再重新开单引号。看着别扭,但这是 shell 的标准做法。

Windows 的情况完全不一样。cmd 不认单引号,必须整体用双引号包,内部双引号用\"转义:

curl -X POST "https://api.example.com/v1/orders" ^ -H "Content-Type: application/json" ^ -d "{\"sku\":\"A-1001\",\"qty\":2}"

注意续行符是^而不是\。PowerShell 里更麻烦,它对双引号内的转义和 cmd 不同,还涉及{}的解析问题。我的建议是:在 Windows 上不要在命令行里直接拼 JSON,一律写成文件,用-d @file.json传。这一条能省掉你八成的时间。

注意:不要把 JSON 用单引号包起来再放到双引号里,也别指望\在所有 shell 里都一样。判断标准很简单——先echo一下你要传的那段字符串,看看输出是不是你期望的样子,再塞进 curl。

3. 请求体变复杂之后:从一行命令到可维护的写法

内联 JSON 只适合字段少、结构平的场景。真实项目里,一个请求体动辄几十个字段、嵌套两三层,还有数组、布尔、null、时间戳,全塞在一行命令里既写不对也维护不了。这时候就该换思路了。

3.1 把 JSON 落到文件里再发

最直接的做法是新建一个payload.json,把内容规规矩矩写进去(编辑器还能帮你做语法高亮和格式校验),然后用@引用:

curl -X POST 'https://api.example.com/v1/orders' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer YOUR_TOKEN' \ --data-binary @payload.json

这里几个细节值得说。

@后面跟文件名,curl 会读取文件内容作为请求体。如果写成@-,表示从标准输入读,可以配合管道使用,比如cat payload.json | curl ... --data-binary @-。

用--data-binary而不是-d,是为了保证文件里的内容一字不差地发出去。虽然 JSON 去掉换行仍然合法,但一旦你以后要加签名字段、要计算内容哈希,任何一点改动都会让签名对不上,排查起来非常痛苦。一开始就用--data-binary,是给未来的自己留后路。

文件名建议带版本或场景后缀,比如payload.create-order.json、payload.update-qty.json。我见过不少人把十几种请求体都塞进一个body.json,改来改去,最后分不清哪个是哪个。

另外一个实用技巧:发送前先做一次语法校验。如果你本机有 Python,一行命令就能验证:

python3 -m json.tool payload.json > /dev/null && echo OK

不 OK 会直接报出出错的行号,比等服务端返回"解析失败"再回来猜快得多。

3.2 变量注入与模板化

文件方式解决了结构问题,但带来了硬编码问题:token、订单号、时间戳每次都要改文件,很烦。常见做法是用占位符加环境变量。

如果 JSON 外层用双引号包(在 shell 里),$VAR会被展开。但更干净的方式是用envsubst之类的工具先把模板渲染成临时文件:

export ORDER_SKU="A-1001" export ORDER_QTY=2 envsubst < payload.tpl.json > /tmp/payload.json curl -X POST 'https://api.example.com/v1/orders' \ -H 'Content-Type: application/json' \ --data-binary @/tmp/payload.json

模板文件里写${ORDER_SKU}、${ORDER_QTY}。这样做的好处是模板可以进版本库,敏感值走环境变量,不会把 token 提交上去。

需要注意的是类型问题。envsubst做的是纯文本替换,如果你的 JSON 里需要数字2而不是字符串"2",模板里就别给占位符加引号。这个坑我踩过——把数量替换成了字符串,服务端反序列化直接报类型不匹配,返回 400,查了半天才发现是模板里的引号没去掉。

3.3 认证头、自定义头的组合

除了Content-Type,实际请求通常还要带认证信息。常见几类:

认证方式请求头写法备注
Bearer Token-H 'Authorization: Bearer xxx'最常见,token 别写进脚本明文
自定义 Key-H 'X-Api-Key: xxx'头名大小写按文档来
签名-H 'X-Sign: xxx'通常与时间戳、请求体内容相关
追踪-H 'X-Request-Id: abc123'排查问题时非常有用

我强烈建议加上X-Request-Id,值用随机串。服务端日志里如果有这个字段,出问题时你能一秒定位到那一条日志,而不用按时间范围去捞。生成方式很简单,uuidgen或者date +%s%N都行。

还有一个头的坑值得单独提:Expect: 100-continue。当请求体超过一定大小(通常是 1024 字节)时,curl 会自动先发一个Expect: 100-continue头,等服务端回复 100 再发 body。这在标准 HTTP 里没问题,但一些老的网关、反向代理处理不好,表现是"命令卡住几秒然后超时"。解决办法是显式禁掉它:

-H 'Expect:'

冒号后面什么都不写,就是这个头被移除的意思。这个技巧在传大 JSON 文件时特别有用,遇到"请求一直不返回"的情况可以先试它。

3.4 响应端处理:只看你想看的那部分

命令发出去只是前半程,后半程是读响应。curl 默认把响应体打到标准输出,格式紧凑、中文可能乱码、几百个字段糊成一片。几个参数能大幅改善体验。

-s静默模式,不显示进度条和错误摘要;-S配合-s使用,静默但仍显示错误信息。这两个组合起来是-sS,脚本里的标配。

-o resp.json把响应体写进文件,-D headers.txt把响应头单独存一份。排查问题时这两份文件很有价值,尤其是响应头里的X-Request-Id、Set-Cookie、Content-Encoding。

-w自定义输出,可以在响应体之后追加状态码、耗时等信息:

curl -sS -o resp.json -w 'code=%{http_code} time=%{time_total}s\n' \ -X POST 'https://api.example.com/v1/orders' \ -H 'Content-Type: application/json' \ --data-binary @payload.json

%{http_code}是状态码,%{time_total}是总耗时,%{time_connect}是建立连接耗时,%{size_download}是下载字节数。把耗时打出来,能快速判断是网络慢还是服务端处理慢。

格式化响应体的首选是jq:

curl -sS -X POST 'https://api.example.com/v1/orders' \ -H 'Content-Type: application/json' \ --data-binary @payload.json | jq .

jq .做美化,jq '.data.id'直接取字段,jq -r去掉引号方便塞进变量。这玩意儿配上 curl,基本能把接口调试的活干完。

4. 一次完整实操:从连通性验证到拿到数据

光讲参数容易散,我把一次完整的联调过程按顺序走一遍,你可以照着复现。

4.1 第一步先别急着发 JSON

拿到一个新接口,我从来不先写完整命令,而是先确认三件事:域名能不能解析、端口通不通、路径对不对。用一个最简单的 GET 探路:

curl -sS -i --max-time 5 'https://api.example.com/v1/orders'

-i表示把响应头一起打出来。这时候你会看到几种结果:200 或 400 说明连通没问题,可以继续;404 说明路径写错了,去看文档;403 说明路径对但没权限,需要检查认证头;连接超时或者Could not resolve host,那问题在网络层,跟 JSON 一点关系都没有,别在这里浪费时间调参数。

这一步的意义在于把变量分开。如果一上来就发完整命令,报错了你不知道是网络问题、路径问题、认证问题还是 body 问题,四个变量搅在一起。先探路,能把排查范围直接砍掉一半。

4.2 用-v看清请求真正长什么样

确认连通之后,加上-v发一次真实请求。-v会打印出 curl 实际发出的请求行、请求头,以及服务端返回的响应头。输出大概长这样:

> POST /v1/orders HTTP/1.1 > Host: api.example.com > Content-Type: application/json > Content-Length: 46 > < HTTP/1.1 201 Created < Content-Type: application/json

重点看两行:Content-Type是不是你期望的值,Content-Length是不是和你估的差不多。如果Content-Length比你想的短很多,说明 body 被 shell 啃掉了一块,引号或者转义出问题了。如果它干脆是 0,说明-d后面的内容被当成空字符串了。

-v和-i的区别要分清:-i只显示响应头加响应体,-v显示整个交互过程,包括请求头。调试请求构造问题时用-v,看返回内容时用-i就够了。如果还嫌不够细,--trace-ascii trace.txt能把每一个字节的收发都记下来,适合排查编码、分块传输这类底层问题。

注意:-v的输出默认走标准错误流,如果你用> resp.json重定向,响应体照样能被正确存下来,不会污染文件。

4.3 加上超时和重试,把命令变成能进脚本的东西

临时敲的命令可以不管超时,但一旦要放进脚本或者定时任务,就必须加约束,否则某次网络抖动就能让整个流程卡死。

curl -sS \ --connect-timeout 3 \ --max-time 15 \ --retry 3 \ --retry-delay 2 \ --retry-connrefused \ -X POST 'https://api.example.com/v1/orders' \ -H 'Content-Type: application/json' \ -H 'Expect:' \ --data-binary @payload.json \ -o resp.json \ -w 'code=%{http_code} time=%{time_total}s\n'

--connect-timeout 3限制建立连接的时间,--max-time 15限制整个请求的时长。这两个值怎么定?我的经验是:连接超时设 3 到 5 秒,因为正常的内网或同城调用建立连接不该超过这个数;总超时按业务耗时设,先跑几次看time_total的分布,取一个比 P99 稍大的值,留出余量但不至于让用户干等。

--retry只对幂等安全的错误重试,包括连接失败、超时、以及部分 5xx 状态码。--retry-connrefused是额外的开关,让连接被拒绝时也重试。但要注意:POST 请求默认也会被重试,如果服务端没有做幂等处理,重试可能造成重复下单。这种情况下要么去掉重试,要么在请求体里带一个唯一业务号,让服务端去重。

还有一个细节:加了--retry之后,拿到的返回值可能是最后一次重试的结果,中间失败的次数不会告诉你。如果你需要知道重试了几次,-w里的%{num_retries}变量可以打出来。

4.4 保存请求和响应,方便回放和对比

联调过程中最浪费时间的事,是"刚才那条命令跑出问题了,但我改了几笔之后复现不出来了"。解决办法很简单:把命令和历史响应都存下来。

我自己的习惯是在项目里建一个debug/目录,每条命令跑完自动存两份文件:resp-<时间戳>.json和headers-<时间戳>.txt。命令本身写进一个history.sh,加上注释说明场景。三次之后你就会发现,回头查"上周那个 400 是怎么解决的"变得特别容易。

对比两次响应也很常用。用diff看两份响应体的差异,用jq -S .先做键排序再比,能过滤掉字段顺序带来的噪音。这招在排查"同一份请求,A 环境成功、B 环境失败"时特别好使。

5. 常见报错与排查速查表

这部分是我这些年攒下来的经验清单,遇到问题可以直接对照。

5.1 状态码类问题:400、415、401、302

状态码常见原因第一步检查
400 Bad Requestbody 结构不合法、字段类型错、缺必填用-v看 Content-Length,用 Python 校验 JSON
415 Unsupported Media Type没写Content-Type: application/json补上这个头,注意冒号后空格
401 Unauthorizedtoken 缺失、过期、格式不对检查头名和Bearer后面的空格
403 Forbidden权限不足、IP 白名单、签名错确认账号权限,核对签名算法
404 Not Found路径错、方法错(用了 GET 打 POST 路由)核对文档路径与方法
405 Method Not Allowed方法用错,或-X写了但被覆盖显式写-X POST
302 Found服务端要求跳转,curl 默认不跟随需要跟进用-L,但要处理 body 丢失
500 Internal Server Error服务端挂了,或你的数据触发异常拿X-Request-Id找服务端日志

重点说两个。

415 的问题是请求头,不是请求体。很多人看到 415 第一反应是"我的 JSON 写错了",实际上服务端压根没解析 body,它是在检查内容类型这一步就拒了。补上-H 'Content-Type: application/json'基本就解决。

302 是个陷阱。加-L跟随跳转,curl 会把 POST 改成 GET 重发,请求体直接丢掉。如果你的接口有 HTTP 到 HTTPS 的跳转,就会遇到"明明请求体没问题,服务端说没收到参数"的怪事。解决办法是加上--post301 --post302 --post303,让 curl 在跳转后继续保持 POST 方法和请求体。这几个参数知道的人不多,但非常关键。

5.2 引号、转义与 shell 吃掉字符

这类问题最隐蔽,因为报错信息不指向根因。判断方法很直接:发之前先 echo。

echo '{"sku":"A-1001","qty":2}'

如果输出和你写的对不上,说明引号就被 shell 处理掉了,curl 收到的就是残缺内容。常见表现有三种。

一是Content-Length偏小。前面提过,用-v一眼能看出来。

二是 JSON 里出现了未转义的换行。多行 JSON 放在双引号里,如果没处理好续行,实际内容会带换行,某些严格解析器会拒绝。

三是变量意外展开。双引号里的$会被 shell 替换成变量值,如果你的 JSON 恰好包含$字符(比如金额字段),就会被吃掉。用单引号或者对$转义可以避免。

还有一类是中文被转成\uXXXX或者显示成乱码。这通常不是 curl 的问题,是终端的编码设置。验证方法是用-o写到文件再看,如果文件里正常、终端里乱码,那就是终端设置,不影响实际请求。

5.3 中文、编码与文件格式

涉及中文的请求体,我吃过两次亏,都是文件格式的锅。

第一次是文件保存成了带 BOM 的 UTF-8。BOM 是文件开头三个不可见字节,JSON 解析器看到它会直接报"非法字符",而且报错位置在第 1 行第 1 列,看着像是内容有问题。解决办法是用编辑器另存为"UTF-8 无 BOM",或者在 Linux 下用sed -i '1s/^\xEF\xBB\xBF//'去掉。

第二次是 Windows 上编辑的文件带了 CRLF 换行。JSON 里如果有换行,CRLF 和 LF 本身不影响解析,但如果你的某个字段值是字符串且需要精确比较,多出来的\r会让比较失败。用file payload.json看一眼,或者cat -A检查行尾。

编码方面还要注意字符集声明。虽然 JSON 标准规定必须用 UTF-8,但有些老服务会读Content-Type里的 charset,没写就按默认编码解析。加上; charset=utf-8更保险,成本为零。

5.4 三个系统上的差异清单

项目Linux / macOSWindows cmdPowerShell
单引号包字符串支持,内容原样不支持支持但有额外解析
续行符\^反引号
双引号内转义\"\"反引号转义
{}解析无问题无问题可能被当脚本块
推荐写法单引号内联文件传 body文件传 body 或curl.exe

PowerShell 那一栏要单独说一句。PowerShell 会把{}当作脚本块的一部分去解析,curl又是Invoke-WebRequest的别名,同一条命令在这里行为完全不同。两个应对办法:一是显式写curl.exe而不是curl,绕开别名;二是干脆不拼内联,全部走文件:

curl.exe -X POST 'https://api.example.com/v1/orders' ` -H 'Content-Type: application/json' ` --data-binary '@payload.json'

这个写法在 PowerShell 里是最省心的,我建议所有 Windows 用户默认就用它。

6. 用了很多年才定下来的几个书写习惯

聊到最后,分享几个不算技术但确实省时间的小习惯,都是我改过很多次才定型的。

第一,参数顺序固定成"地址、头、体、输出"。先 URL,再所有-H,再 body 相关,最后输出控制。固定顺序的好处是扫一眼就知道这条命令干了什么,也方便用脚本批量改。我见过有人把-H夹在-d后面,虽然能跑,但读起来费劲。

第二,凡是超过三个字段的 JSON,一律走文件。这个界限是我踩坑踩出来的。三个字段以内,内联改起来快;超过三个,引号和转义的维护成本就超过文件方式的成本了。

第三,命令里永远带-sS。不带的话,进度条会污染输出,混进jq里就报解析错误;只带-s不带-S,出错时一片安静,你会以为请求成功了。

第四,调试阶段一定加-v,进脚本一定去掉。-v的输出很有用,但会写到标准错误,脚本里如果不处理,日志会被塞满。

第五,把跑通的命令存成带注释的脚本片段。我电脑上有个snips.sh,里面全是按业务场景分类的 curl 命令,每条上面一行注释写着"这个接口要传 X-Request-Id,不然会 400"这种只有自己踩过才知道的信息。三个月后再回来看,这些注释比任何文档都值钱。

再补一个小技巧:如果服务端返回的是紧凑 JSON 且中文变成\uXXXX,别急着怀疑编码,先jq .一下,jq默认会把 Unicode 转义还原成中文。如果jq输出正常而直接输出乱码,那就是终端的问题,请求本身没错。判断清楚这一点,能省掉很多无效的排查时间。

返回列表