← 返回题目列表

HTTP 条件请求是什么?ETag 和 Last-Modified 有什么区别?

高频 中等 第 14 / 32 题 更新于 2026/07/31
HTTP缓存条件请求ETagLast-Modified304

简化版

HTTP 条件请求是客户端带上条件头,让服务器判断资源是否变化,再决定返回完整内容还是 304 Not Modified。常见组合是 If-None-Match 配合 ETagIf-Modified-Since 配合 Last-ModifiedETag 是资源版本标识,可以比时间更精确;Last-Modified 基于修改时间,精度通常到秒,容易受时间粒度和文件更新时间影响。强缓存不发请求,协商缓存会发条件请求。

详细版

条件请求主要用于协商缓存和并发更新保护。

响应头请求头常见用途
ETagIf-None-Match判断资源版本是否一致
Last-ModifiedIf-Modified-Since判断资源修改时间是否晚于客户端缓存
ETagIf-Match更新前确认版本未变化
Last-ModifiedIf-Unmodified-Since更新前确认资源未被修改

浏览器缓存资源过期后,会带上条件请求头询问服务器。如果资源没变,服务器返回 304,响应体为空或很小,浏览器复用本地缓存;如果资源变了,服务器返回 200 和新内容。优先级上通常 ETag 高于 Last-Modified

完整版教学

一、条件请求解决什么问题

HTTP 缓存分两类:强缓存和协商缓存。强缓存命中时浏览器不请求服务器;强缓存过期后,并不一定要重新下载完整资源,而是可以发条件请求。

浏览器缓存过期
    |
    v
带 If-None-Match / If-Modified-Since 请求服务器
    |
    +-- 资源未变化 -> 304 -> 继续用本地缓存
    |
    +-- 资源已变化 -> 200 -> 下载新内容

条件请求的价值是减少传输体积,同时保证客户端拿到的资源没有过期。

二、ETag 与 If-None-Match

ETag 是服务器给资源生成的版本标识。客户端第一次请求:

HTTP/1.1 200 OK
ETag: "v1-abc"
Cache-Control: max-age=60

缓存过期后,客户端再次请求:

GET /app.js HTTP/1.1
If-None-Match: "v1-abc"

如果服务器发现当前资源仍然对应 "v1-abc",返回:

HTTP/1.1 304 Not Modified
ETag: "v1-abc"

浏览器就继续使用本地缓存的 app.js

三、Last-Modified 与 If-Modified-Since

Last-Modified 表示资源最后修改时间。客户端缓存后,会在后续请求中带上:

If-Modified-Since: Wed, 21 Oct 2026 07:28:00 GMT

服务器比较资源最后修改时间。如果没有更新,返回 304;如果更新时间更晚,返回 200 和新资源。

它的缺点也明显:

  • 时间精度通常到秒,一秒内多次修改可能判断不准;
  • 资源内容未变但修改时间变了,可能误判为需要重新下载;
  • 分布式服务器时间不一致会导致判断混乱。

四、ETag 为什么通常更可靠

ETag 可以根据内容 hash、版本号、构建产物指纹或数据库版本生成,因此比单纯时间戳更灵活。

对比项ETagLast-Modified
判断依据资源版本标识修改时间
精度可由服务器控制通常秒级
分布式一致性需要统一生成规则依赖机器时间
适合场景精确协商缓存静态文件简单缓存

面试里可以说:ETag 更精确,Last-Modified 更简单;两者同时存在时,服务端通常优先使用 ETag

五、条件请求不只用于缓存

条件请求还可以避免并发更新覆盖。比如客户端修改文章前先拿到:

ETag: "article-v3"

提交更新时带:

PUT /article/1 HTTP/1.1
If-Match: "article-v3"

如果服务器当前版本已经不是 article-v3,说明有人先改了,服务器可以返回 412 Precondition Failed,避免“后提交覆盖先提交”。

这和数据库乐观锁很像:ETag 相当于版本号,If-Match 相当于更新条件。

六、304 响应到底有没有响应体

304 Not Modified 的语义是资源未修改,客户端应使用已有缓存。它通常不带消息体,核心价值是节省响应体传输。

但 304 响应仍然可以携带与缓存相关的头,例如:

  • Cache-Control
  • ETag
  • Expires
  • Last-Modified

客户端会用这些头更新本地缓存元信息。不要把 304 理解成错误,它是缓存协商成功的结果。

七、常见误区与追问

  • 误区:协商缓存命中时不会发请求。 协商缓存需要向服务器发条件请求,只是资源未变化时返回 304。
  • 误区:ETag 和 Last-Modified 完全等价。 ETag 是版本标识,Last-Modified 是时间标识,精度和可靠性不同。
  • 误区:304 会返回完整资源内容。 304 通常没有响应体,浏览器使用本地缓存。
  • 误区:ETag 一定是文件内容 hash。 ETag 的生成策略由服务器决定,可以是 hash、版本号或其他标识。
  • 追问:ETag 和 Last-Modified 同时存在谁优先? 通常优先使用 ETag,因为它能更精确表达资源版本。
  • 追问:If-Match 有什么用? 它可用于并发更新保护,只有资源版本匹配时才允许修改。

八、加强记忆

条件请求就是“先问服务器资源有没有变”。ETag -> If-None-Match 看版本,Last-Modified -> If-Modified-Since 看时间;没变返回 304,变了返回 200 和新内容。强缓存是不请求,协商缓存是发条件请求。回答时再补一句:If-Match 可以做乐观并发控制,说明你不只会背浏览器缓存,还理解 HTTP 条件语义。