curl POST命令行发送数据的完整用法示例
同样一句POST,为什么一次能成一次报错?curl发POST报错的第一大类原因,不是命令写错,而是命令写对了、但对不上服务端要收的格式。一个典型排障案例:客户用curl给某电商API发登录请求,本地环境返回200,搬到生产脚本里换参数就一直返回400。
命令看起来一样:
curl -X POST https://api.example.com/login -d "user=alice&pass=xxx"
服务端返回{"error":"invalid content type"}。追下去发现:开发时API允许application/x-www-form-urlencoded,生产版本升级到只接受application/json。同一句命令里-d "user=alice&pass=xxx"默认发的是表单编码,不是JSON。命令没错,是”数据类型→Content-Type→Body编码”这条链路错位。
POST请求成败的第一判断轴:三件事必须匹配。
数据类型:表单、JSON、文件、原始二进制Content-Type Header:告诉服务端”我发的是什么”Body编码方式:实际写进请求体的数据格式
三者错位任一段,服务端拿到的就是错位数据,大多返回400或415,少数返回200但业务字段错乱,后者更难排。
curl发POST,几种数据类型该怎么写?按数据类型给四组命令模板,直接对照用。
类型速查表:
数据类型
Content-Type
curl参数
典型场景
表单键值对
application/x-www-form-urlencoded
-d或--data
传统登录、简单表单提交
JSON
application/json
-H "Content-Type: application/json" -d '{...}'
现代REST API、微服务接口
文件上传、多字段
multipart/form-data
-F "file=@..."
图片上传、附件表单
原始body(不做编码)
自定义
--data-binary @文件
Webhook、二进制协议、原样XML
1. 表单键值对(x-www-form-urlencoded)
curl -X POST https://api.example.com/login \
-d "username=alice&password=xxx"
-d默认Content-Type就是application/x-www-form-urlencoded,不用手动加Header。字段值有中文、空格、特殊字符时,用--data-urlencode自动做百分号编码:
curl -X POST https://api.example.com/search \
--data-urlencode "q=北京 出租房" \
--data-urlencode "page=1"
2. JSON body
curl -X POST https://api.example.com/orders \
-H "Content-Type: application/json" \
-d '{"item":"iphone","qty":2,"user_id":10086}'
必须显式加-H "Content-Type: application/json"。不加的话,服务端按表单解析,整串JSON会被当成一个奇怪的字段名。JSON值里有单引号时,外层用双引号,内部字段引号转义。
3. 文件上传(multipart/form-data)
curl -X POST https://api.example.com/upload \
-F "file=@/path/to/photo.jpg" \
-F "description=产品图" \
-F "category=electronics"
-F会自动切到multipart/form-data,不需要手动加Content-Type。同一请求可以带多个-F,文件用@前缀,普通字段直接写。
4. 原始body(不做任何编码转换)
curl -X POST https://api.example.com/webhook \
-H "Content-Type: application/xml" \
--data-binary @payload.xml
--data-binary与-d的差别:-d会把body里的换行去掉,--data-binary一字节不改按原样发。发XML、二进制协议、hash校验敏感的载荷时,一律用--data-binary。
关于-X POST与-d的关系:-d出现时,curl自动切到POST方法,-X POST可以省。反过来只写-X POST不带-d,发的是空body。要发GET携带body(少见)、或走PUT/PATCH,才需要显式-X。
POST请求的Header与鉴权,怎么处理最不容易踩坑?Header是POST请求里最容易被忽视的部分。除Content-Type外,常见需要显式带的Header有三类。
1. 鉴权类
# Bearer Token
curl -X POST https://api.example.com/data \
-H "Authorization: Bearer eyJhbGc..." \
-H "Content-Type: application/json" \
-d '{"query":"select 1"}'
# Basic Auth(curl 内置支持,不用手动拼)
curl -X POST -u alice:secret https://api.example.com/data -d '{...}'
# 自定义 API Key
curl -X POST https://api.example.com/query \
-H "X-API-Key: sk-abc123..." \
-H "Content-Type: application/json" \
-d '{...}'
2. Cookie与会话保持
# 第一次登录,把 Cookie 保存到文件
curl -c cookies.txt -X POST https://site.example.com/login \
-d "user=alice&pass=xxx"
# 后续请求带上刚才的 Cookie
curl -b cookies.txt -X POST https://site.example.com/api/action \
-H "Content-Type: application/json" \
-d '{...}'
-c保存Cookie到文件,-b读文件带上。这套组合替代手写-H "Cookie: sessionid=xxx",适合模拟登录后的连续请求。
3. User-Agent与常见附加Header
curl -X POST https://api.example.com/data \
-H "User-Agent: Mozilla/5.0 ..." \
-H "Accept: application/json" \
-H "Accept-Language: zh-CN,zh;q=0.9" \
-H "Referer: https://site.example.com/" \
-H "Content-Type: application/json" \
-d '{...}'
部分API要求带明确的UA与Referer才允许POST。这类要求写在API文档里,不带就返回403或401,报错信息通常不明说是Header缺失,容易误判成鉴权失败。
常见Header错位对照:
症状
大概率原因
400 Bad Request
Content-Type与Body编码不匹配
401 Unauthorized
Token过期、Header拼写错误(如Authorization少一个z)
403 Forbidden
UA、Referer、Origin不符合服务端预期
411 Length Required
手写body时没让curl自动算Content-Length,少见但要注意
415 Unsupported Media Type
Content-Type服务端不认(如发form却写成application/json)
200但业务字段错
Body拼接错误(如JSON键名大小写错、多余转义)
命令写出来了,怎么自测确实发对了?发POST之后的自测三件套:-v、-i、-w。
1. -v看完整详情
curl -v -X POST https://api.example.com/data \
-H "Content-Type: application/json" \
-d '{"a":1}'
-v打印完整的请求Header、请求Body、响应Header、响应Body、TLS握手细节。排障时第一个用它,能看到”我们实际发出去的东西”是不是自己以为发的那样。
2. -i只看响应Header
curl -i -X POST https://api.example.com/data -d 'test=1'
看服务端返回的状态码、Content-Type、Set-Cookie等,不看body。适合只关心接口是否走通、返回了什么状态的场景。
3. -w打印时序、连接细节
curl -o /dev/null -s -w \
"code=%{http_code}\ntime=%{time_total}s\nsize=%{size_download}B\n" \
-X POST https://api.example.com/data -d 'test=1'
-w用格式化字符串输出,%{http_code}是状态码、%{time_total}是总耗时、%{time_connect}是建连时间等。写脚本批量自测时用这个采集单次请求的时序,做基准对照。
4. --output保存响应体
curl -X POST -o response.json https://api.example.com/data -d '{...}'
响应体大的时候不直接打屏,写到文件里再看。
排查失败请求的建议顺序:
加-v看请求Body与Header是不是你以为的看响应状态码,对照上表的错位表定位用-w打时间戳,判断是超时还是被拒抽本地curl命令换个环境跑,判断是命令问题还是网络问题(比如换台机器、换代理出口)
带代理的POST请求,命令行怎么写?curl带代理走-x或--proxy参数,格式协议://用户名:密码@主机:端口。
HTTP/HTTPS代理(带账密验证)
curl -x http://username:password@proxy.example.com:8080 \
-X POST https://api.target.com/data \
-H "Content-Type: application/json" \
-d '{"query":"..."}'
HTTPS目标+代理隧道(CONNECT)
# 对 HTTPS 目标,curl 会自动向代理发 CONNECT 建隧道
curl --proxy http://user:pass@proxy.example.com:8080 \
-X POST https://api.target.com/data -d '{...}'
SOCKS5代理
curl --socks5 user:pass@proxy.example.com:1080 \
-X POST https://api.target.com/data -d '{...}'
白名单验证的代理(不用密码,IP需提前加入代理服务的白名单)
curl -x http://proxy.example.com:8080 \
-X POST https://api.target.com/data -d '{...}'
我们青果网络的代理支持HTTP、HTTPS、SOCKS5三种协议,验证方式白名单或账密二选一,白名单支持256个(来源:青果网络官网)。写脚本时优先用账密(可跨环境用同一组凭据),白名单适合固定服务器的采集机。
带代理的常见错误:
症状
原因
407 Proxy Authentication Required
代理需要账密但没给,或账密拼写错
502 Bad Gateway
代理服务本身故障,或代理无法访问目标
Connect timeout
代理端口错、代理服务未启动、防火墙拦截
SSL certificate problem
代理是自签证书,加-k跳过校验(仅测试环境)
Empty reply from server
目标站点触发频次门槛,或代理IP进入了限速名单
用代理发POST的自测:先不加代理跑一遍确认命令没问题,再加代理跑;失败时用-v看是”到代理”失败还是”代理到目标”失败——前者在建连阶段就报错,后者能看到CONNECT或代理响应。
在我们青果网络的企业级采集实践里,POST请求走代理最常踩的坑不是命令,是”同一批任务复用同一个出口IP连续发几百个POST,触发目标站点频次门槛”。这时不是换命令写法,是换代理调度策略——高频POST场景更适合走短效代理或隧道代理,让每次请求或按窗口切换出口IP。
做数据采集里的POST请求选青果哪款代理IP?POST请求跑不通的根因常不在命令,而在数据类型、Header、Body编码链路是否对齐;换到生产用代理时,链路还多了”IP调度策略与目标站点频次门槛”这一环。基于这条判断,选型落到我们青果网络的两类产品:高频POST采集需要每次请求或按窗口换出口,隧道代理(国内按请求数计费¥360/月起、海外超级池1000GB阶梯4元/GB,来源:青果网络官网)让curl命令不用改,IP切换在服务端隧道内完成;需要固定出口、长会话保持鉴权Cookie的场景,独享代理(国内按通道计费¥99/月起、存活0-1440分钟可调,来源:青果网络官网)更合适,同一批POST请求在同一出口下完成,鉴权Cookie不会因换IP失效。评估期把自己业务里最频繁的一组POST命令在两种代理上各跑连续4小时,拿成功率与鉴权保持情况做基准,比对参数表上的池规模更接近选型时该看的指标。
常见问题Q1:curl发POST时-d和--data-raw有什么区别?
A:两者都是发body,但对特殊字符处理不同。-d会解释@文件名语法(从文件读内容)、去掉body里的换行;--data-raw不做任何解释,原样发。当body内容以@开头,或者你想保留原始换行、二进制数据的每个字节,用--data-raw或--data-binary。日常发form或简单JSON用-d够。
Q2:curl发POST中文乱码怎么办?
A:三步排查。先看命令行终端是否UTF-8(Linux/macOS默认UTF-8,Windows CMD可能是GBK);再看curl是否显式指定编码(通过-H "Content-Type: application/json; charset=utf-8");最后看服务端Content-Type响应头声明的编码。三者一致就不会乱码。Body里的中文用--data-urlencode自动做百分号编码,是最省心的方式。
Q3:POST请求返回200但业务数据错误,怎么排查?
A:优先加-v看实际发出去的Body是不是你以为的那样。常见错位:JSON键名大小写错(user_idvsuserId)、数字被当成字符串("qty":"2"而非"qty":2)、外层引号不匹配导致JSON被截断、-d与shell变量拼接时被shell二次转义。把-v的输出保存下来,拿Body与API文档字段对照,大多能定位。
Q4:命令行POST请求怎么跳过SSL证书校验?
A:测试环境或已知代理是自签证书时,加-k(或--insecure)跳过校验。生产环境不建议关掉。SSL校验失败通常是真实的证书问题,应该修证书而不是关校验。企业级采集里如果对端确实用自签证书,用--cacert /path/to/ca.pem显式指定根证书,比全局跳过更安全。
Q5:一台采集机上大量并发POST请求,怎么用curl高效跑?
A:curl是单请求工具,并发一般用xargs -P N、GNU parallel、或写脚本用curl库(libcurl / pycurl)。命令级并发用cat urls.txt | xargs -P 20 -I {} curl -X POST {} -d '...'起20并发。我们青果网络在网站采集器场景观察到:并发数与目标站点频次门槛是配套的,一味加并发不换IP,请求会集中命中限速。做高并发POST采集时,并发数与代理调度策略要成对设计,不是单点决策。
Q6:POST请求走代理时,HTTPS目标的证书是校验代理的还是校验目标的?
A:校验目标的。curl走HTTP CONNECT隧道与代理建立通道后,TLS握手是”本机↔目标”直连的,代理只做转发不解密——除非代理本身做了MITM(通常企业内网审计代理才这样)。所以-k或--cacert处理的是目标站的证书,不是代理的。