curl发送JSON POST的最小可用命令是什么?
最小可用命令包含三个必要元素:-X POST指定方法、-H "Content-Type: application/json"声明body格式、-d携带JSON字符串。三者缺一,服务端就有可能按表单或纯文本解析请求体。
curl -X POST \
-H "Content-Type: application/json" \
-d '{"keyword":"电动牙刷","page":1}' \
https://api.example.com/search命令参数的作用如下:
| 参数 | 作用 | 是否必需 |
|---|---|---|
-X POST | 显式指定HTTP方法 | 使用-d时curl会隐式设为POST,但建议显式写 |
-H "Content-Type: ..." | 告诉服务端body格式 | JSON场景必需 |
-d / --data | 携带请求体 | 必需 |
-H "Accept: ..." | 告诉服务端希望的响应格式 | 建议加,避免服务端返回错误格式 |
一个更完整的最小命令示例:
curl -X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"keyword":"电动牙刷","page":1}' \
https://api.example.com/search-d参数的一个隐性行为要注意:默认使用Content-Type: application/x-www-form-urlencoded,即使body内容是JSON,服务端也会按表单解析。因此-H "Content-Type: application/json"不是可选项,而是必选项。
另外一个容易被忽略的细节是body内的单双引号。上面示例把JSON字符串用单引号包裹'{"k":"v"}',这样双引号可以直接写而不用转义,最省心。如果shell不支持单引号或body含shell变量,就要改用双引号包裹并对内部双引号做\"转义,出错概率会高很多。网站采集器调用第三方查询接口时,建议统一约定用单引号包裹body写法,避免团队成员踩坑。
JSON请求体来源有几种写法,各自适合什么场景?
JSON请求体有四种主流来源:内联字符串、文件读取、标准输入管道、heredoc块。四种写法适合不同的body体积、动态性、调试便利度需求。
| 来源方式 | 命令写法 | 适合场景 |
|---|---|---|
| 内联字符串 | -d '{"k":"v"}' | body简短、静态、快速调试 |
| 文件读取 | -d @body.json | body较大、多次复用、版本化管理 |
| 标准输入管道 | -d @- | body由上游程序动态生成 |
| heredoc块 | -d @-<<EOF ... EOF | 脚本中拼接多行JSON、可读性优先 |
内联字符串:最短的写法,适合快速调试或body简短的场景。
curl -X POST \
-H "Content-Type: application/json" \
-d '{"keyword":"电动牙刷","page":1,"size":20}' \
https://api.example.com/search文件读取:body存在独立文件里,用@前缀引用。适合请求体较大、需要版本化管理、多次复用的场景。
# body.json 内容
# {"query":"电动牙刷","filters":{"price":{"min":100,"max":500}}}
curl -X POST \
-H "Content-Type: application/json" \
-d @body.json \
https://api.example.com/search标准输入管道:body由上游程序生成后通过管道传入,用@-表示从stdin读取。适合脚本化调度、body动态拼接的场景。
echo '{"keyword":"电动牙刷","timestamp":"'"$(date -u +%FT%TZ)"'"}' | \
curl -X POST \
-H "Content-Type: application/json" \
-d @- \
https://api.example.com/logheredoc块:脚本中拼接多行JSON时可读性最佳,配合shell变量插值方便。
KEYWORD="电动牙刷"
curl -X POST \
-H "Content-Type: application/json" \
-d @- \
https://api.example.com/search <<EOF
{
"keyword": "$KEYWORD",
"page": 1,
"size": 20,
"filters": {
"category": "personal_care"
}
}
EOF四种写法的关键取舍是body来源与调试成本。网站采集器批量提交查询任务时-d @file最合适,body固定、可版本化管理;广告监测每分钟上报动态数据时管道或heredoc更灵活。日常联调建议先用内联字符串跑通,再切到文件或管道方式做批量化。
需要注意的是heredoc块里的shell变量插值行为——用<<EOF时shell会做变量替换和命令替换,用<<'EOF'加单引号时会保留字面量。如果body里既有shell变量又有原生美元符号,可以用\$转义单个美元符号,或者干脆分两段拼接。
中文和特殊字符怎么保证POST请求不乱码?
乱码问题的根源是字符编码不一致。curl本身不对body做编码转换,body是什么编码就发送什么编码。保证不乱码要满足三个条件:源文件UTF-8编码、Content-Type声明charset、shell环境LANG支持UTF-8。
第一步,确认源文件与shell环境为UTF-8:
# 查看 shell 语言环境
echo $LANG
# 期望输出:zh_CN.UTF-8 或 en_US.UTF-8
# 查看文件编码
file -bi body.json
# 期望输出:application/json; charset=utf-8第二步,Content-Type显式声明charset:
curl -X POST \
-H "Content-Type: application/json; charset=utf-8" \
-d '{"keyword":"电动牙刷"}' \
https://api.example.com/search第三步,body中的特殊字符按JSON规范转义:
| 字符 | JSON转义写法 | 说明 |
|---|---|---|
" | \" | body用单引号包裹时可直接写,用双引号包裹时要转义 |
\ | \\ | 路径分隔符、正则表达式常用 |
| 换行 | \n | JSON字符串内换行必须转义 |
| Tab | \t | 制表符 |
| 中文 | UTF-8原文或\uXXXX | 推荐UTF-8原文,可读性更好 |
一个包含转义的完整示例:
curl -X POST \
-H "Content-Type: application/json; charset=utf-8" \
-d '{"query":"关键词 with \"引号\"","path":"C:\\logs\\a.txt","note":"多行\n内容"}' \
https://api.example.com/log如果body来自变量拼接,用jq预先生成合法JSON是较稳妥的做法:
KEYWORD='关键词 with "引号"'
BODY=$(jq -n --arg kw "$KEYWORD" '{keyword: $kw, page: 1}')
curl -X POST \
-H "Content-Type: application/json; charset=utf-8" \
-d "$BODY" \
https://api.example.com/searchjq -n --arg会自动处理转义,避免手动写\"时踩坑。舆情监测这类场景需要提交长文本给NLP API做分析,用jq预生成JSON能显著降低出错率。
除了jq,Python的json.dumps、Node的JSON.stringify都能在脚本中生成安全的JSON。选哪种取决于团队技术栈。核心原则是"永远不要手动拼接JSON字符串"——只要body里出现用户输入或外部变量,就用工具生成。手动拼接的隐患不仅是转义错误,还包括无效字符注入、编码错乱等更深层问题。
需要鉴权的接口,Authorization头怎么加?
主流API鉴权分四种:Bearer Token、Basic Auth、API Key放Header或Query、自定义签名。四种在curl中都通过-H携带对应头字段完成。
| 鉴权类型 | curl写法 | 典型使用 |
|---|---|---|
| Bearer Token | -H "Authorization: Bearer <TOKEN>" | OAuth 2.0、大部分SaaS API |
| Basic Auth | -u user:pass 或 -H "Authorization: Basic <base64>" | 老旧API、内部系统 |
| API Key放Header | -H "X-API-Key: <KEY>" | 大部分商业API |
| API Key放Query | 拼接到URL ?api_key=<KEY> | 简易API,不推荐生产使用 |
Bearer Token,OAuth 2.0体系里最常见:
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"keyword":"电动牙刷"}' \
https://api.example.com/searchBasic Auth,curl内置的-u更简洁,会自动做base64编码:
curl -X POST \
-H "Content-Type: application/json" \
-u "username:password" \
-d '{"action":"query"}' \
https://api.example.com/internalAPI Key放Header,很多SaaS商业API的默认方式:
curl -X POST \
-H "Content-Type: application/json" \
-H "X-API-Key: sk_live_xxxxxxxxxxxxx" \
-d '{"campaign_id":"C-2026-001"}' \
https://api.example.com/ads/report自定义签名,例如HMAC,需要预先计算签名后写进头:
TIMESTAMP=$(date -u +%s)
SIGNATURE=$(echo -n "$TIMESTAMP" | openssl dgst -sha256 -hmac "$SECRET_KEY" | awk '{print $2}')
curl -X POST \
-H "Content-Type: application/json" \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-Signature: $SIGNATURE" \
-d '{"data":"..."}' \
https://api.example.com/sign鉴权头的三条常见坑:
- Token/Key不要写死在命令里,用环境变量或从secrets manager拉取,避免误提交到git
- Bearer Token前的
Bearer空格不能省,一些服务端严格校验会返回401 - Basic Auth的用户名密码含特殊字符时用
-u user:pass比手写base64更稳,curl会自动处理
广告监测调用广告平台API这类场景,通常用API Key + HMAC签名双因子鉴权,签名部分可以封装成一个shell函数复用。
生产环境POST的超时、重试、大请求体怎么处理?
生产级POST请求要配置四类保护:连接超时、总超时、失败重试、大body专用参数。默认curl不设超时,网络波动时可能挂起,重试也需要显式开启。
| 场景 | 参数 | 推荐配置 |
|---|---|---|
| 连接超时 | --connect-timeout | 5-10秒 |
| 总超时 | --max-time | 30-60秒,视业务定 |
| 失败重试次数 | --retry | 3次 |
| 重试间隔 | --retry-delay | 从2秒起指数递增 |
| 重试触发条件 | --retry-connrefused、--retry-all-errors | 视需求开 |
| 大body上传 | -T 或 --data-binary @file | 避免-d对二进制做处理 |
一个覆盖生产保护参数的完整命令:
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d @body.json \
--connect-timeout 10 \
--max-time 60 \
--retry 3 \
--retry-delay 2 \
--retry-max-time 120 \
--retry-all-errors \
https://api.example.com/submit大请求体的特殊处理:-d默认会对body内容做换行符处理,即去掉\n,如果body是二进制或需要精确保留字节,用--data-binary:
curl -X POST \
-H "Content-Type: application/json" \
--data-binary @large_body.json \
https://api.example.com/upload超过10MB的body推荐用-T,等价于HTTP PUT但很多API也接受,或分片上传接口。同时打开gzip压缩能显著减少传输量:
curl -X POST \
-H "Content-Type: application/json" \
-H "Content-Encoding: gzip" \
--data-binary @<(gzip -c large_body.json) \
https://api.example.com/upload网站采集器批量提交查询任务时--retry-all-errors很有用,能覆盖连接错误、HTTP 5xx、超时等多种失败情形;舆情监测调用NLP API处理长文本时--max-time要放宽到60秒以上,避免正常处理被超时打断。
通过代理调用海外或内网API时命令怎么写?
curl通过代理调用API的核心参数是-x(--proxy)。支持HTTP、HTTPS、SOCKS4、SOCKS5四种协议,鉴权用--proxy-user。
| 协议 | URL写法 | 说明 |
|---|---|---|
| HTTP代理 | -x http://host:port | 明文HTTP代理 |
| HTTPS代理 | -x https://host:port | curl与代理之间也走HTTPS |
| SOCKS5 | -x socks5://host:port | 建议加h后缀让DNS在代理端解析 |
| SOCKS5+DNS远程 | -x socks5h://host:port | 推荐,DNS通过代理走,避免DNS泄露 |
HTTP代理示例:
curl -X POST \
-H "Content-Type: application/json" \
-x http://proxy.example.com:8080 \
-d '{"keyword":"electric toothbrush"}' \
https://api.example.com/search代理需要鉴权时:
curl -X POST \
-H "Content-Type: application/json" \
-x http://proxy.example.com:8080 \
--proxy-user "username:password" \
-d @body.json \
https://api.example.com/searchSOCKS5代理,走DNS远程解析:
curl -X POST \
-H "Content-Type: application/json" \
-x socks5h://proxy.example.com:1080 \
--proxy-user "username:password" \
-d '{"keyword":"electric toothbrush"}' \
https://api.example.com/search代理配置的三条实用做法:
- 用环境变量而不是每条命令都写
-x:export https_proxy=http://user:pass@proxy:8080 - 内网某些域名要跳过代理时用
--noproxy:--noproxy "*.internal.com,localhost" - 排查代理是否生效用
-v观察是否有Connected to proxy一行
海外API调用是代理最常见的使用场景之一。广告监测拉取海外广告平台数据、跨境物流信息查询走物流商官方API,都需要通过海外出口代理才能访问到目标地域的完整数据。
代理稳定性直接影响curl命令的成功率。生产环境建议把-x配合--connect-timeout和--max-time一起用,代理不通时快速失败,避免拖垮整体任务调度。同时把代理鉴权凭证放到环境变量或密钥管理系统里,命令行只引用变量名,减少凭证泄露风险。
curl调试POST请求失败时可观测性怎么做?
curl的可观测性有三层:-v看请求响应头、--trace-ascii看完整报文、-w看时序与状态。三层从粗到细,配合使用能覆盖90%以上的调试需求。
| 参数 | 输出内容 | 适合场景 |
|---|---|---|
-v 或 --verbose | 请求头、响应头、连接过程 | 大部分调试第一站 |
--trace-ascii <file> | 完整请求响应报文含body | 需要看服务端返回的详细body |
-w 或 --write-out | 自定义输出,含状态码、时间、大小 | 生产监控、性能分析 |
-i | 响应含头部输出到stdout | 简单查看响应头 |
-o /dev/null | 丢弃响应body | 只关心时序或状态码 |
基础调试用-v:
curl -v -X POST \
-H "Content-Type: application/json" \
-d '{"keyword":"电动牙刷"}' \
https://api.example.com/search输出会包含请求行>和响应行<的每一行,一眼能看出鉴权是否发出、Content-Type是否正确、服务端返回什么状态码。
看完整报文用--trace-ascii:
curl --trace-ascii /tmp/curl.trace \
-X POST \
-H "Content-Type: application/json" \
-d @body.json \
https://api.example.com/submittrace文件里能看到完整的请求body和响应body,适合排查服务端"400 Bad Request"但不知道body哪里错的场景。
生产监控与时序分析用-w:
curl -o /dev/null -s -w \
'HTTP: %{http_code}\nTotal: %{time_total}s\nConnect: %{time_connect}s\nTTFB: %{time_starttransfer}s\nSize: %{size_download}\n' \
-X POST \
-H "Content-Type: application/json" \
-d @body.json \
https://api.example.com/submit输出示例:
HTTP: 200
Total: 1.234s
Connect: 0.089s
TTFB: 0.923s
Size: 512-w常用的可观测变量:
| 变量 | 含义 |
|---|---|
%{http_code} | HTTP响应状态码 |
%{time_total} | 请求总耗时 |
%{time_connect} | TCP连接建立耗时 |
%{time_starttransfer} | 首字节返回耗时,即TTFB |
%{size_download} | 响应body大小,单位字节 |
%{url_effective} | 实际请求的URL,含重定向后 |
网站采集器把curl当作快速探针使用时,-w的输出可直接接入监控系统,做请求成功率、延迟、体积的三维观测;广告监测的定时任务里加上-w能快速定位是TTFB高还是连接慢。
FAQ
Q:-d和--data-binary的区别是什么?
-d会剥掉body里的\r和\n换行符,适合发送单行JSON字符串。--data-binary会精确保留body的所有字节,适合发送二进制、多行JSON、或需要精确控制字节的场景。传JSON时如果body是格式化过的多行文本,用--data-binary更安全。
Q:curl POST JSON时收到400 Bad Request,怎么排查?
按四步排查:一看-v输出确认Content-Type是否为application/json;二用--trace-ascii看服务端返回的错误详情;三本地用jq . body.json验证JSON格式是否合法;四检查是否有BOM头或不可见字符,用file -bi body.json看编码是否为UTF-8。
Q:curl POST时需要维持cookie会话,怎么写?
用-c cookies.txt保存服务端返回的cookie到文件,用-b cookies.txt在后续请求带上cookie。两个参数可以同时用,实现完整的会话保持。舆情监测这类需要登录态的场景常这样用。
Q:POST请求需要跟随重定向,命令怎么加?
加-L即--location。默认curl不跟随3xx重定向,加-L后会自动跟随。跟随重定向时如果原请求是POST,curl会根据3xx状态码类型决定是否保持POST方法——303改GET、307和308保持POST。要强制保持用--post301、--post302、--post303。
Q:怎么在shell脚本中判断curl POST是否成功?
推荐用-o body -w "%{http_code}"分离body和状态码。示例:
STATUS=$(curl -o /tmp/resp.json -s -w "%{http_code}" \
-X POST -H "Content-Type: application/json" \
-d @body.json https://api.example.com/submit)
if [ "$STATUS" = "200" ]; then
echo "OK"
else
echo "Failed: $STATUS"
fi这个模式比解析-v输出稳定。
Q:POST请求返回压缩响应比如gzip或deflate,怎么解压?
加--compressed,curl会自动声明Accept-Encoding并对响应做解压。示例:curl --compressed -X POST -H "Content-Type: application/json" -d @body.json https://api.example.com/search。响应压缩率高的API比如返回大列表的搜索接口,加上后能显著减少传输时间。
Q:curl POST时如何跳过HTTPS证书校验?仅调试用
加-k(--insecure)。这个参数只在调试自签证书或过期证书的内部环境时用,生产环境严禁使用,会失去HTTPS的中间人防护。正确做法是把根证书通过--cacert导入。
