三个属性是什么
HTTP 用三个属性描述每个方法的语义:安全指方法只读取、不改变资源状态;幂等指同一请求执行一次与执行多次对服务器产生的可观察效果相同;可缓存指响应允许被缓存存储复用。这三个属性不是学术名词,而是工程判断依据:只有幂等的请求才适合在网络超时后自动重试,只有安全的请求才能被预取与爬虫访问,可缓存的响应才能交给中间节点。
属性定义
| 安全 | 不改变资源状态的只读语义,见规范关于安全方法的章节 |
|---|---|
| 幂等 | 重复执行的可观察效果与一次相同,重试安全 |
| 可缓存 | 响应允许被浏览器与共享缓存存储并复用 |
| 依据 | 定义见规范中方法属性一节,重定向与补丁方法另有说明 |
| 用途 | 决定能否自动重试、能否预取、能否加缓存 |
方法属性总表
| 方法 | 安全 | 幂等 | 可缓存 | 典型用途 |
|---|---|---|---|---|
| 读取资源 | 是 | 是 | 是 | 读取内容 |
| 只取响应头 | 是 | 是 | 是 | 探测元数据 |
| 探测能力 | 是 | 是 | 否 | 跨域预检 |
| 链路诊断 | 是 | 是 | 否 | 请求回显排查 |
| 全量替换 | 否 | 是 | 否 | 替换或创建 |
| 删除资源 | 否 | 是 | 否 | 移除资源 |
| 提交数据 | 否 | 否 | 极少 | 提交、创建、复杂查询 |
| 部分修改 | 否 | 通常否 | 否 | 按补丁文档局部修改 |
| 建立隧道 | 否 | 否 | 否 | 代理建连 |
按幂等性决定重试
按幂等性决定重试
# 读取与全量替换可以放心重试
for i in 1 2 3; do curl -sf -o /dev/null https://api.example.com/items/1 && break; sleep $((i*2)); done
# 提交数据必须带上幂等键才能重试
curl -X POST https://api.example.com/orders -H 'Idempotency-Key: k-001' -H 'Content-Type: application/json' -d '{}'怎么用这三个属性
- 网络超时后的自动重试只对幂等方法开放,非幂等方法必须靠幂等键兜底
- 需要预加载或后台抓取的地址只放安全方法,避免爬虫一爬就把数据删了
- 设计接口时先判断语义属于哪一类,再决定用哪个方法,而不是反过来
- 给响应加缓存前先确认请求是读取语义,写操作加缓存会出现数据错乱的严重事故
- 排查「重复扣款」「重复创建」类问题时,先看客户端是否对非幂等方法做了自动重试
幂等说的是服务器端可观察效果相同,不要求响应码完全一致:把同一条记录删两次,第二次返回未找到也是合规的幂等实现。
把非幂等方法当幂等方法使用(例如让客户端对提交请求做自动重试),会在网络抖动时产生重复数据;反过来,把本可幂等的更新做成无法重试的形式,则会在超时时留下状态不明的数据。
四个易错认识
- 安全与幂等是两个独立维度:删除是幂等的,但它不安全,因为改变了资源状态
- 缓存的正确性依赖请求语义,给写操作加缓存会让用户看到别人的操作结果
- 重试策略应按方法属性分层配置,而不是全局打开自动重试
- 排查重复数据时先看客户端重试日志,再确认服务端幂等键是否真的生效
落地建议
- 把浏览器私有缓存与共享缓存分清,涉及个人数据时默认只允许浏览器缓存
- 预取与后台抓取只针对安全方法,更简单的做法是让所有写操作都使用非读取方法
- 在接口文档里标注每个方法与路径的幂等性,客户端重试策略就能照着实现