PUT 是什么
PUT 用请求体完整替换目标资源的表示,是幂等方法:同一个请求执行一次与执行多次,对服务器产生的可观察效果相同。这一点让它天然适合自动重试——网络超时后重发不会产生额外副作用。RFC 9110 §9.3.4 允许它创建资源也允许它更新,具体由服务端策略决定;创建成功通常返回创建状态码,替换成功常返回无内容状态码。理解它的关键是把它当成「替换」,而不是「补充字段」。
基本信息
| 名称 | PUT(RFC 9110 §9.3.4) |
|---|---|
| 作用 | 创建或全量替换目标资源 |
| 特性 | 幂等,重试安全;修改了资源状态,因此不安全 |
| 成功码 | 创建返回创建码,替换返回无内容码或成功码 |
| 地址语义 | 地址由客户端指定,服务端不负责生成 |
典型使用场景
- 按已知标识更新资源:调用方自己确定资源地址与完整内容
- 上传固定路径的配置文件或对象:内容整体覆盖,天然幂等
- 做幂等的补偿操作:超时后重发不会造成副作用叠加
- 同步外部数据:以完整快照覆盖本地记录,避免差量合并的歧义
- 替换用户资料全量字段:能接受未提供字段被清空的场景
全量替换示例
全量替换示例
curl -i -X PUT https://api.example.com/users/101 \
-H 'Content-Type: application/json' \
-d '{"name":"alice","age":30}'
# 替换成功通常会返回无内容状态码,不带响应体
# 携带条件校验可以避免覆盖他人的修改
curl -i -X PUT https://api.example.com/users/101 \
-H 'If-Match: v17' -H 'Content-Type: application/json' \
-d '{"name":"alice","age":31}'与提交方法的对比
| 对比项 | 替换方法 | 提交方法 |
|---|---|---|
| 作用对象 | 客户端指定的具体地址 | 集合资源,地址由服务端决定 |
| 幂等性 | 幂等,可安全重试 | 非幂等,重试可能产生重复 |
| 请求体语义 | 完整表示,缺字段即清空 | 部分数据或指令 |
| 创建行为 | 是否创建由服务端策略决定 | 通常用于创建 |
| 典型成功码 | 无内容或成功 | 创建成功码并给出新地址 |
使用要点
- 把它当成替换:客户端必须先取到完整资源,再修改后整体提交
- 需要局部修改时改用补丁方法,用替换方法只传部分字段会把其余字段清空
- 并发场景配合条件校验头,避免后写覆盖先写
- 对创建行为不要想当然,服务端可以只支持更新而返回未找到
替换与合并的差别是最大的坑:多数实现会按请求体重建资源,未提供的字段被清空或恢复默认值。想要「只改一个字段」,请使用补丁语义,而不是把替换当成更新。
在并发编辑场景下直接替换会静默丢失他人的修改:A 与 B 都基于同一版本编辑,后提交者覆盖先提交者。加入条件校验后,版本不匹配会直接拒绝而不是悄悄覆盖。
与补丁方法怎么取舍
- 字段少且需要整体覆盖时用替换,语义清晰、幂等、重试安全
- 只改少数字段时用补丁方法,避免未提供的字段被清空
- 需要服务端生成资源地址时用提交方法,替换方法要求客户端自己决定地址
- 并发编辑场景给替换加上条件校验,不匹配直接拒绝而不是静默覆盖
上线前的三点自查
- 确认客户端提交的是完整表示,而不是只带改动过的字段
- 确认服务端对创建行为有明确约定,并在文档里写清楚
- 确认并发编辑路径有条件校验,避免静默覆盖他人的修改