本文要点
缓存里的响应不是永久有效的
这是本文要回答的核心问题
浏览器重新加载页面时,发出的请求会体现上面这套验证机制

本文目录
先分清两个响应标头各自记录什么
如果你在浏览器开发者工具的 Network 面板里看一条响应,可能会同时看到 ETag 和 Last-Modified 两个标头。它们都是缓存验证用的标识,但记录的内容不同。
Last-Modified 记录的是资源最后一次修改的时间,格式是一个 HTTP 日期。MDN 的缓存文档给出的例子是:Last-Modified: Tue, 22 Feb 2022 22:00:00 GMT。服务器可以从操作系统的文件系统中获取这个修改时间,对提供静态文件的情况来说比较容易做到。
ETag 记录的是服务器为这个资源生成的一个值。MDN 明确说明,ETag 响应标头的值是服务器生成的任意值,服务器对于生成值没有任何限制,可以根据自己选择的任何方式自由设置,例如主体内容的散列或版本号。文档举的例子是 ETag: "33a64df5"。
所以两者的区别可以这样记:Last-Modified 回答“这个资源什么时候改过”,ETag 回答“服务器给这个版本贴了什么标签”。标签是什么形式、怎么来的,不在本文范围内。
一个自建情境(示例,不是对某个真实网站的记录):你在练习目录里维护一个自建页面,用本地或公开地址打开它,在 Network 面板里点开这条响应,分别找到 ETag 和 Last-Modified 两行,把它们的值抄在笔记里。这一步只用来观察两个标头长什么样。
缓存过期后,客户端拿哪个标头去问服务器
缓存里的响应不是永久有效的。MDN 把存储的响应分成两种状态:新鲜和过期。判断标准是存活时间,也就是响应生成以来经过的时间。只要响应保持新鲜,它就会被用来兑现客户端请求;一旦过期,就不能直接重用了。
但过期的响应不会立即被丢弃。HTTP 有一种机制,可以通过询问源服务器把旧响应转换为新响应,这称为验证,有时也叫重新验证。验证是通过包含 If-Modified-Since 或 If-None-Match 请求标头的条件请求完成的。
对应关系是这样的:
- 响应里带 Last-Modified,客户端验证时把它放进 If-Modified-Since 请求标头。
- 响应里带 ETag,客户端验证时把它放进 If-None-Match 请求标头。
MDN 给出的 If-Modified-Since 例子是:客户端发送 If-Modified-Since: Tue, 22 Feb 2022 22:00:00 GMT,询问服务器自指定时间以来是否有任何改变。如果内容自指定时间以来没有更改,服务器响应 304 Not Modified。这个响应只表示“没有变化”,因此没有响应主体,只有一个状态码,传输大小非常小。
If-None-Match 的例子是:客户端把缓存响应的 ETag 值放进 If-None-Match: "33a64df5"。如果服务器为请求的资源确定的 ETag 值与请求中的 If-None-Match 值相同,服务器返回 304 Not Modified;如果服务器确定资源现在应该具有不同的 ETag 值,则改为返回 200 OK 和资源的最新版本。
所以判断顺序可以定成:先看响应里有哪些验证标识,再决定请求里带哪个条件标头。响应里只有 Last-Modified,就带 If-Modified-Since;只有 ETag,就带 If-None-Match。
两个标识同时存在时,验证以哪个为准
这是本文要回答的核心问题。MDN 的备注写得很明确:RFC 9110 建议服务器在发送 200 响应时,尽可能同时发送 ETag 和 Last-Modified;在缓存重新验证过程中,如果同时存在 If-Modified-Since 和 If-None-Match,则对验证器而言,If-None-Match 具有优先级。
把这句话落到操作上:当响应里同时有 ETag 和 Last-Modified,客户端发起验证时可能两个条件标头都带上,但服务器判断时以 If-None-Match 为准。也就是说,ETag 对应的验证结果优先于 Last-Modified 对应的验证结果。
MDN 还解释了为什么两个都值得保留。如果你仅考虑缓存,可能会认为 Last-Modified 没有必要。然而,Last-Modified 不仅对缓存有用;它还是一种标准 HTTP 标头,内容管理系统会利用它显示最后修改时间,爬虫会利用它调整抓取频率,此外还有其他各种用途。因此,从整个 HTTP 生态系统的角度来看,最好同时提供 ETag 和 Last-Modified。
一个自建情境(示例,不是对某个真实网站的记录):你在练习目录里放一个自建页面,在 Network 面板里找到一条同时带 ETag 和 Last-Modified 的响应,然后触发一次重新加载,观察请求标头里是不是两个条件标头都出现了。这一步只用来观察请求里带了什么,不据此推断服务器内部怎么判断。
重新加载时请求里会带哪些条件标头
浏览器重新加载页面时,发出的请求会体现上面这套验证机制。MDN 给出的简化视图是:
GET / HTTP/1.1
Host: example.com
Cache-Control: max-age=0
If-None-Match: "deadbeef"
If-Modified-Since: Tue, 22 Feb 2022 20:20:20 GMT文档说明,来自 Chrome、Edge 和 Firefox 的请求看起来很像上面的;来自 Safari 的请求看起来会有点不同。
这个请求里有三处值得注意。第一,Cache-Control: max-age=0 指定“重用存活时间为 0 或更少的响应”,因此中间存储的响应不会被重用。第二,请求通过 If-None-Match 和 If-Modified-Since 两个标头进行验证。第三,两个条件标头同时出现时,按上一节的优先级,If-None-Match 起决定作用。
强制重新加载是另一种情况。MDN 给出的请求是:
GET / HTTP/1.1
Host: example.com
Pragma: no-cache
Cache-Control: no-cache文档说明,由于这不是带有 no-cache 的条件请求,因此可以确定会从源服务器获得 200 OK。也就是说,强制重新加载不带条件标头,它绕过缓存响应,直接拿最新版本,不进入验证流程。
这两种重新加载的差别,正好对应本文要分清的两件事:普通重新加载是“带着验证标识去问”,强制重新加载是“不问,直接要新的”。
用自建页面观察一次验证的输入和输出
下面是一套只操作自建练习文件的观察方法,不涉及任何真实网站,也不修改系统设置。
准备:在练习目录里放一个自己写的页面文件,例如 exercise/cache-demo/index.html,内容自己写,不要放任何敏感信息。用本地或公开地址打开它。
第一步,记录响应里的验证标识。打开开发者工具的 Network 面板,刷新页面,点开这条请求,在响应标头里找 ETag 和 Last-Modified。把两行原样抄进笔记。如果只找到其中一个,就只记这一个。
第二步,触发一次普通重新加载。观察这次请求的请求标头,看有没有出现 If-None-Match 和 If-Modified-Since,以及它们的值是不是和上一步抄下的 ETag、Last-Modified 对应。
第三步,看状态码。如果服务器判断资源没有变化,会返回 304 Not Modified;如果判断有变化,返回 200 OK 和最新版本。
第四步,做一次强制重新加载,再观察请求标头里还有没有条件标头。按 MDN 的说明,强制重新加载不带条件请求,预期会从源服务器得到 200 OK。
需要提醒的是:以上是编辑整理的观察步骤,不是对某个真实网站的测试记录。不同浏览器在重新加载时的请求写法可能不同,MDN 也指出 Safari 的请求看起来会有点不一样。所以观察结果以你当场看到的为准,不要用本文的描述去替代实际记录。
验证标识能帮你判断什么,不能判断什么
把这两个标头用起来之前,先划清边界。
能判断的:这次请求的资源相对缓存里的版本有没有变化。304 Not Modified 表示没有变化,可以继续用缓存里那份;200 OK 表示有变化,服务器给了最新版本。这个判断的依据是验证标识的比对结果。
不能判断的:资源内容好不好、页面有没有被收录、网站可不可信。这些都不在 ETag 和 Last-Modified 回答的范围内。
还有一点要分清:ETag 的值是服务器生成的任意值,MDN 明确说服务器对生成值没有任何限制。所以你不能从 ETag 的写法反推资源内容、版本号规则或服务器实现方式。本文也不涉及服务器怎么生成 ETag。
Last-Modified 也有它的局限。MDN 指出,服务器可以从操作系统的文件系统中获取修改时间,但这也存在一些问题,例如时间格式复杂且难以解析,分布式服务器难以同步文件更新时间。文档说明,为了解决这些问题,ETag 响应标头被标准化作为替代方案。这解释了为什么两个标识会同时存在,也解释了为什么验证时 If-None-Match 优先。
适用范围:本文只讲 ETag 与 Last-Modified 作为验证标识的含义、If-None-Match 与 If-Modified-Since 的对应关系,以及两者同时存在时的优先级。不讲服务器生成 ETag 的实现方式,不涉及具体编程语言,也不涉及缓存策略怎么配置。
观看知识要点视频 18 秒
18秒无旁白要点导览,文字来自已审核正文;完整步骤、条件及参考资料见下方。
参考资料
以下原始资料提供本文依据;请结合日期、适用条件和产品说明查阅。
请结合原始资料的适用条件阅读。
返回浏览器工具 →