首页/网络/协议速查/If-None-Match 不匹配前置条件
HTTP 头与缓存70 条

If-None-Match 不匹配前置条件

条件请求头:当 ETag 与给定值不匹配时才执行;GET 场景命中即返回 304,写场景可用于「不存在才创建」。

协议速查网络更新于 2026-10-13

If-None-Match 是什么

If-None-Match 是条件请求头:当资源的当前 ETag 与客户端给出的值不匹配时,请求条件才成立。它在读场景里用来做缓存校验——内容没变就返回 304,省掉重复传输;在写场景里可以表达「资源不存在才创建」,防止覆盖已有对象。它与 If-Modified-Since 同时出现时,规范要求以 ETag 的判定优先。

基本信息

方向请求头
取值一个或多个 ETag,或用通配符 "*"
读场景命中内容未变,返回 304 Not Modified
写场景不成立资源已存在,返回 412 Precondition Failed
通配语义"*" 表示「资源不存在时条件成立」
规范RFC 9110 §13.1.2

典型使用场景

  • 静态资源缓存校验:浏览器带上次收到的 ETag,命中则回 304 只传头
  • 接口轮询:内容未变时不传正文,显著降低带宽
  • 幂等创建:用 If-None-Match: * 保证「只在不存在时写入」
  • 配合 CDN:回源校验由源站决定是否 304,减少回源流量
  • 避免覆盖:上传前先检查对象是否已存在

缓存校验与条件创建

缓存校验与条件创建
# 读场景:内容未变返回 304
curl -si -H 'If-None-Match: "v17"' https://static.example.com/app.js | head -1
# HTTP/1.1 304 Not Modified
# 写场景:只有资源不存在时才创建,已存在则 412
curl -si -X PUT https://api.example.com/keys/k1 \
  -H 'If-None-Match: *' -d 'value'
# 先取 ETag 再校验
ETAG=$(curl -sI https://static.example.com/app.js | awk 'tolower($1)=="etag:"{print $2}' | tr -d '\r')
curl -si -H "If-None-Match: $ETAG" https://static.example.com/app.js | head -1

用法与结果

用法条件成立时条件不成立时
GET + If-None-Match: ETag回 200 与完整内容回 304,不传正文
GET + If-None-Match: *资源不存在时回 404资源存在时回 200
PUT + If-None-Match: *资源不存在,执行创建已存在,回 412 拒绝覆盖
PUT + If-None-Match: ETag版本不同,执行更新版本相同,回 412
两者同时出现时 If-None-Match 优先,If-Modified-Since 被忽略:这是规范明确规定的,也是「为什么我改了时间戳但缓存还是旧的」这类疑问的答案。缓存设计上建议以 ETag 为主。
304 响应不携带正文,但应带上必要的缓存头(如 Cache-Control、ETag),否则客户端可能在下一次请求时缺少判断依据,缓存策略出现抖动。
把 If-None-Match 用在写接口时要确认服务端的并发语义:两个请求同时带 If-None-Match 通配值到达时,只有真正做了原子判定的实现才能挡住第二个,先查后写在并发下依然会重复创建。

易错点

  • 用 If-None-Match 做「不存在才创建」时忘了配合服务端的原子性保证,两个并发请求可能同时创建成功
  • 把 304 当成错误码处理:它是缓存命中,属于正常路径,监控里要单独归类
  • ETag 由内容哈希生成却忽略了压缩差异(gzip 前后摘要不同),导致缓存命中率偏低
  • 依赖 If-Modified-Since 单独做缓存校验:时间精度到秒且受时钟影响,不如 ETag 可靠

数据来源与参考

  • RFC 9110 §13.1.2 If-None-Match

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌