前置条件失败的含义
412 Precondition Failed 表示请求里的条件头不成立,服务器因此拒绝执行。最常见的场景是乐观并发控制:客户端带上 If-Match 与自己看到的 ETag,如果资源已经被别人改过(当前 ETag 不匹配),服务器就回 412 而不是默默覆盖。理解 412 的关键是它一定由客户端主动发出的条件头触发,而不是服务器单方面的判断。
基本信息
| 名称 | 412 Precondition Failed |
|---|---|
| 语义 | 条件请求中的前置条件未满足 |
| 规范 | RFC 9110 §15.5.13,条件请求见 RFC 9110 §13 |
| 常见条件头 | If-Match、If-None-Match、If-Unmodified-Since、If-Modified-Since |
| 重试特性 | 请求本身是幂等的,客户端可重新拉取最新版本后重放 |
条件头对应的结果
| 条件头 | 条件不满足时 | 典型用途 |
|---|---|---|
| If-Match | 412 | 防止覆盖他人修改(乐观锁) |
| If-None-Match | 对应 304 或 412 | 避免重复创建、配合缓存校验 |
| If-Unmodified-Since | 412 | 按时间做写入保护 |
| If-Modified-Since | 返回 304 或正常响应 | 条件 GET 节省带宽 |
乐观锁更新
乐观锁更新
curl -si -X PUT https://api.example.com/docs/7 \
-H 'If-Match: "v5"' -H 'Content-Type: text/markdown' -d @doc.md
# 若当前 ETag 是 "v6" → HTTP/1.1 412 Precondition Failed
# 正确处理:重新 GET 拿到最新内容与 ETag,合并后再带新的 If-Match 重试
curl -si https://api.example.com/docs/7 | grep -i etag典型使用场景
- 多人协作编辑文档,避免后写覆盖先写
- 配置中心下发配置时校验版本,防止并发覆盖
- 文件上传与对象存储的条件写入,保证只对预期版本操作
- 接口层拒绝「无版本号更新」,用 428 要求先带上条件头
412 与 409 的边界:412 由条件头触发,语义清晰且可自动重试;409 表示资源状态冲突(如唯一键重复、状态机不允许),通常需要业务判断。实现时不要混用,否则调用方的重试策略会失准。
返回 412 时应同时在响应体里给出当前版本或最新 ETag,客户端才能一次性完成「拉新、合并、重试」,否则会出现反复 412 的请求风暴。
注意弱验证器:带 W/ 前缀的弱 ETag 只保证语义等价而不保证字节一致,用于 If-Match 做写入保护时需服务端明确支持,否则应改用强验证器或版本号字段。