POST 是什么
POST 把实体数据提交给目标资源,请服务器按该资源自身的语义处理。RFC 9110 §9.3.3 明确它既不安全也不幂等:同一请求重复发送可能创建多条记录。POST 与 PUT 的关键分工是——POST 通常作用于集合资源,由服务端决定新资源的 URI;PUT 作用于客户端已经知道的 URI 并做全量替换。创建成功一般返回 201 Created,并用 Location 头指出新资源的地址。
基本信息
| 名称 | POST |
|---|---|
| 作用 | 提交实体,由目标资源按自身语义处理 |
| 规范 | RFC 9110 §9.3.3;幂等性见 §9.2.2 |
| 特性 | 非安全 + 非幂等 + 通常不可缓存 |
| 必备头 | Content-Type 描述请求体的媒体类型 |
典型使用场景
- 创建资源:注册账号、下单、发布内容
- 表单提交:登录、搜索、文件上传(配合多部分表单类型)
- 复杂查询:条件多到 URL 放不下时用请求体传递
- 命令型接口:发送验证码、发起导出任务等动作触发
- 回调与通知:多数平台约定用 POST 推送事件
创建资源与幂等重试
创建资源与幂等重试
curl -i -X POST https://api.example.com/users \
-H 'Content-Type: application/json' \
-d '{"name":"alice","email":"alice@example.com"}'
# HTTP/1.1 201 Created
# Location: /users/101
# 带幂等键的写法:超时后重试不会重复创建
curl -i -X POST https://api.example.com/orders \
-H 'Idempotency-Key: 8f1c-2026-1013-0001' \
-H 'Content-Type: application/json' -d '{"sku":"A1","qty":1}'成功后选哪个状态码
| 场景 | 推荐码 | 关键点 |
|---|---|---|
| 创建了新资源 | 201 Created | 用 Location 给出新资源地址 |
| 只提交处理、无新资源 | 200 或 204 | 204 不带响应体 |
| 异步受理(导出、批处理) | 202 Accepted | 给出进度查询地址 |
| 重复提交被幂等去重 | 200 或 201 | 返回首次处理结果,不要报错 |
POST 不保证幂等:网络超时后重试可能创建两条订单。支付、下单、扣款类接口必须引入幂等键或业务唯一约束做去重,仅在客户端做防重复点击远远不够。
幂等键应由客户端生成、服务端持久化并保留一段时间,重复请求返回首次结果。只用数据库唯一索引只能防重复落库,无法让重试请求拿到与首次一致的响应内容。
幂等键的落地要点
- 键由客户端生成并在重试时原样复用,服务端只认键,不认这是第几次请求
- 服务端把键与首次处理结果一起持久化,重复请求直接回放首次结果而不是重新执行
- 键的保留期要覆盖最长的重试窗口,太短会退化成完全不去重
- 键的作用范围要绑定用户与业务类型,避免不同用户之间互相顶掉对方的键
- 成功与失败都要记录键的状态,否则失败之后的正常重试会被误判为重复提交
请求体类型怎么选
| 类型 | 适用 | 注意 |
|---|---|---|
| 结构化数据 | 接口调用、嵌套对象 | 必须显式声明类型,否则可能被按表单解析 |
| 表单编码 | 传统页面表单、简单键值 | 不支持嵌套结构,复杂值需自行序列化 |
| 多部分表单 | 含文件上传的混合提交 | 分隔符必须与报文一致,否则解析直接失败 |
| 纯文本或二进制 | 日志上报、文件直传 | 缺少类型声明时服务端可能直接拒绝处理 |
表单提交无法直接发送结构化数据:要么改用表单编码按字段拆解,要么由脚本代为发起请求。跨域场景下浏览器还会先发预检请求,服务端必须正确响应预检,否则表现为请求根本发不出去。
异步受理只代表「已收到」,不代表「已完成」:返回 202 之后必须给出可查询进度的地址,并在任务真正结束时改变该资源的可观察状态,否则调用方无法判断最终结果,只能盲目轮询或放弃。