curl POST 请求实战:JSON、表单、文件与安全重试
用本地占位端点练习 curl POST 的 JSON、form-urlencoded 和文件上传,再系统验收请求头、状态码、响应体、超时、重试与幂等性。
作者Yiyao
curl 的 POST 请求可以提交一份新数据,也可以要求服务端执行一个动作。命令本身很短,但要让请求可诊断、可复现,必须同时明确请求体格式、Content-Type、状态码与响应体,还要为重试设置不会悄悄制造重复数据的规则。
本文使用 http://localhost:3000/api/posts 作为本地占位端点,用来演示命令的形状;它不是 Arcvenza 已确认的 API。如果只想访问一个公开网站观察响应,可以使用 https://example.com/,但它是网站首页而不是有文档的 POST 接口,发送 POST 可能被拒绝。
先写清请求契约
写 curl 之前,先记录方法、URL、必需请求头、请求体结构、成功状态码和错误结构。下面的验收条件是:本地处理器收到预期字段,返回已约定的 2xx 状态,并返回可以解析的 JSON。即使 curl 进程退出码为 0,4xx 或 5xx 仍然表示应用层请求失败。
1. 使用 application/json 提交 JSON
当服务端需要嵌套对象、布尔值、数字或明确的 API schema 时,JSON 通常更合适。请求体作为一个字符串传入,因此要注意当前 shell 的引号规则。
curl --request POST "http://localhost:3000/api/posts" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data '{"title":"curl 演示","published":false}'
输入验收:服务端应收到一个 JSON 对象,其中 title 是 curl 演示,published 是 false。输出验收:返回 2xx 状态,并得到类似 {"id":"local-id","title":"curl 演示","published":false} 的响应体。这里的 id 只是本地示例字段,不代表 Arcvenza 提供此类服务。
2. 使用 form-urlencoded 提交表单字段
当字段比较扁平,或服务端沿用传统 HTML 表单约定时,可以使用 URL 编码表单。--data-urlencode 会处理空格和保留字符;显式写出 Content-Type 能让线路格式更清楚。
curl --request POST "http://localhost:3000/api/posts" \
--header "Content-Type: application/x-www-form-urlencoded" \
--header "Accept: application/json" \
--data-urlencode "title=curl 表单演示" \
--data-urlencode "tag=developer tutorials"
输入验收:服务端收到名为 title 和 tag 的两个字段。输出验收:处理器把它们作为字符串解析,并返回文档规定的 2xx 响应。如果服务端要求 JSON,那么即使 URL 和方法都正确,这个请求体仍然是错误的。
3. 使用 multipart/form-data 上传文件
请求中包含文件时使用 multipart 表单。使用 -F 后,curl 会自动生成 multipart boundary;不要手写 boundary,也不要覆盖 curl 生成的 Content-Type。
curl --request POST "http://localhost:3000/api/uploads" \
--header "Accept: application/json" \
--form "file=@./sample.txt;type=text/plain" \
--form "purpose=curl-post-tutorial"
输入验收:本地存在可读取的 ./sample.txt,并额外发送 purpose 字段。输出验收:服务端确认 file 字段、媒体类型和文件大小。如果文件不存在,curl 会在发送请求之前失败;先检查路径和权限。
请求头、状态码与响应体
Content-Type 说明你发送的请求体格式,Accept 说明你希望服务端返回哪些格式,两者作用不同。201 Created 通常表示创建了资源,200 OK 表示请求以正常响应完成,400–499 表示请求或凭据需要修正,500–599 表示服务端或上游依赖失败,最终仍应以具体 API 契约为准。
curl --request POST "http://localhost:3000/api/posts" \
--header "Content-Type: application/json" \
--data '{"title":"检查响应"}' \
--dump-header response.headers \
--output response.json \
--write-out "status=%{http_code}\ntime=%{time_total}s\n"
验收方式:response.headers 保存状态码和响应头,response.json 保存响应体,终端最后一行打印数字状态码和总耗时。不要因为响应体非空就判定成功;先判断状态码,再校验业务字段。
超时与重试
同时设置连接超时和总超时。--connect-timeout 限制建立连接的等待时间,--max-time 限制整个传输过程。只对适合重复的失败重试,例如临时连接失败,或服务端明确说明可以重试的 429/5xx。
curl --request POST "http://localhost:3000/api/posts" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: local-curl-demo-001" \
--data '{"title":"可重试演示"}' \
--connect-timeout 5 \
--max-time 20 \
--retry 3 \
--retry-delay 2 \
--retry-max-time 30
Idempotency-Key 只有在服务端有文档并真正执行幂等语义时才有意义。没有这个契约时,超时结果可能是不确定的:服务端也许已经创建数据,只是客户端没有收到响应。除非你理解重复副作用,否则不要对改变状态的 POST 直接使用 --retry-all-errors。
用一段文字做重试决策表
服务端尚未收到请求体前就发生传输失败:通常可以考虑重试。收到 429 并带有 Retry-After:等待指定时间,且操作允许重复时再试。收到 500 或 503:只有 API 明确允许,并且请求具备幂等语义时才重试。收到 400、401、403 或 422:修正请求或凭据,不要原样重试。上传后超时:先用幂等键或对账标识查询结果,再决定是否再次发送同一 POST。
在接入真实服务前完成验收
先对本地处理器或获准的测试服务运行 JSON、表单和文件三条命令,逐项检查收到的 Content-Type、解析后的字段、文件元数据、返回状态、响应体和耗时。不要把凭据写进 shell 历史,也不要在教程中放真实 token。准备把流程接到 Arcvenza 时,请从 /documentation 和 /quick-start-guides 的真实说明开始;/products/crawler-console 是产品页面,不能据此推断存在某个 POST API。
可以继续阅读 Arcvenza 的 文档、快速入门指南,或查看 Crawler Console 产品页面。连接生产 URL 前,请再次确认当前 API 契约。
