跳到正文
效率工具实用笔记关于本站
浏览器工具

浏览器普通重新加载和强制重新加载:请求头里多了什么

约 8 分钟阅读AI 辅助整理

普通重新加载的请求头带 Cache-Control: max-age=0 和 If-None-Match、If-Modified-Since;强制重新加载带 Cache-Control: no-cache 和 Pragma: no-cache。前者是条件验证请求,后者不是,因此强制重新加载可确定从源服务器得到 200 OK。

本文要点

  1. max-age=0 写在请求里,按文档的解释,它指定“重用存活时间为 0 或更少的响应”——因此,中间存储的响应不会被重用

  2. 按文档的说明,no-cache 指令不会阻止响应的存储,而是阻止在没有重新验证的情况下重用响应

  3. 这是两种重新加载最实际的区别

浏览器普通重新加载和强制重新加载:请求头里多了什么的知识要点示意图
依据已审核正文摘取要点制作的示意图,非实物照片;请结合正文中的条件与范围阅读。要点摘自已审核正文;完整条件与说明见正文。查看高清图解 ↗
本文目录

两种重新加载的请求头并排看差在哪

如果你对同一个页面分别做普通重新加载和强制重新加载,两次请求的头字段不一样。按 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

强制重新加载的请求大致是:

GET / HTTP/1.1
Host: example.com
Pragma: no-cache
Cache-Control: no-cache

差别集中在三处:普通重新加载带 max-age=0 加两个条件验证字段;强制重新加载带 no-cache,并多一个 Pragma: no-cache。文档对这两份示例都附了同一句说明:来自 Chrome、Edge 和 Firefox 的请求看起来很像上面的写法,来自 Safari 的请求看起来会有点不同。

本文只讲这两种重新加载在请求头字段上的差别,以及它们分别可能得到 304 还是 200。不涉及浏览器菜单怎么点,也不写 fetch 的 cache 模式写法。

普通重新加载:max-age=0 与两个验证字段各做什么

普通重新加载的请求头里,Cache-Control: max-age=0 和 If-None-Match、If-Modified-Since 是两组作用不同的字段。

max-age=0 写在请求里,按文档的解释,它指定“重用存活时间为 0 或更少的响应”——因此,中间存储的响应不会被重用。文档还说明,浏览器在重新加载期间使用 max-age=0 是出于向后兼容的原因:在 HTTP/1.1 之前的许多过时实现中不理解 no-cache。

If-None-Match 和 If-Modified-Since 是验证字段。文档说明,验证是通过包含 If-Modified-Since 或 If-None-Match 请求标头的条件请求完成的。If-None-Match 里放的是之前响应里 ETag 的值,If-Modified-Since 里放的是之前响应里 Last-Modified 的时间。

所以普通重新加载的请求头可以这样读:先用 max-age=0 表示不直接复用中间存储的响应,再用两个条件字段去问服务器这个资源从上次那个版本到现在改过没有。

强制重新加载:no-cache 与 Pragma 在文档里的位置

强制重新加载的请求头里出现的是 Cache-Control: no-cache 和 Pragma: no-cache,文档给出的这份简化示例里没有 If-None-Match 和 If-Modified-Since。

按文档的说明,no-cache 指令不会阻止响应的存储,而是阻止在没有重新验证的情况下重用响应。真正阻止存储的是 no-store;强制重新加载用的是 no-cache,不是 no-store。

Pragma: no-cache 在文档里只与 Cache-Control: no-cache 并列出现在强制重新加载的请求示例中,文档没有单独解释它的含义或作用。本文不替它补一层解释,只记录它在示例里的位置:它和 Cache-Control: no-cache 一起出现,而普通重新加载的示例里没有它。

文档对强制重新加载的定性是:这不是带有 no-cache 的条件请求。这一点决定了下一节的状态码结果。

分别可能拿到 304 还是 200

这是两种重新加载最实际的区别。

强制重新加载的结果,文档写的是确定表述:由于这不是带有 no-cache 的条件请求,因此你可以确定你会从源服务器获得 200 OK。也就是说,强制重新加载得到的是 200,不是 304。

普通重新加载带了条件验证字段,属于条件请求。文档在 ETag/If-None-Match 部分说明:如果服务器为请求的资源确定的 ETag 标头的值与请求中的 If-None-Match 值相同,则服务器将返回 304 Not Modified;如果服务器确定请求的资源现在应该具有不同的 ETag 值,则服务器将其改为 200 OK 和资源的最新版本进行响应。

所以对普通重新加载,能确定的是它发出了条件请求;至于这次拿到 304 还是 200,取决于服务器对验证字段的判断结果。文档没有把“普通重新加载必然得到这两种结果之一”写成一句整体断言,本文也不这样写。

304 和 200 在响应体上差在哪

知道会拿到哪个状态码之后,还要知道这两个码在响应体上的区别,否则容易误判“页面没更新”。

按文档对 304 的说明:304 响应仅表示“没有变化”,因此没有响应主体,只有一个状态码,所以传输大小非常小。文档给出的 304 响应示例里仍然带着 Content-Type、Date、Last-Modified 和 Cache-Control: max-age=3600,但没有正文。收到该响应后,客户端将存储的过期响应恢复为有效的,并可以在剩余时间内重复使用它。

200 则不同。文档在讲 If-None-Match 时说明,如果服务器确定资源现在应该有不同的 ETag 值,就返回 200 OK 和资源的最新版本。也就是说,200 会带着新的响应体回来。

所以看到 304 时,不要以为请求失败了;它表示服务器确认资源没变,浏览器继续用本地那份。看到 200 时,说明这次拿到了服务器返回的版本。

If-None-Match 和 If-Modified-Since 同时出现以谁为准

普通重新加载的请求头里,If-None-Match 和 If-Modified-Since 可能同时出现。这时按文档给出的优先级判断。

文档在 ETag/If-None-Match 部分的备注里写明:RFC 9110 建议服务器在发送 200 响应时,尽可能同时发送 ETag 和 Last-Modified;在缓存重新验证过程中,如果同时存在 If-Modified-Since 和 If-None-Match,则对验证器而言,If-None-Match 具有优先级。

这句话对读请求头有直接意义:两个条件字段都在时,先看 If-None-Match 对应的 ETag 是否匹配。

文档还补充了一句,说明为什么 Last-Modified 仍然值得保留:它不仅对缓存有用,还是一种标准 HTTP 标头,内容管理系统会利用它显示最后修改时间,爬虫会利用它调整抓取频率。所以两个字段同时出现不是冗余,只是验证时 If-None-Match 优先。

用自建练习页观察这两种请求的检查顺序

如果你想自己看一遍这两种请求头的差别,可以按下面的顺序做。以下步骤是编辑整理的观察方法,不是对某个真实网站的测试记录。

1. 准备一个自建练习页。在练习目录里放一个自己写的 HTML 文件,例如 exercise/reload-demo.html,内容随意,只用来观察请求。不要拿正在维护的线上页面直接试。

2. 打开开发者工具的 Network 面板,先做一次普通重新加载,找到这条文档请求,展开请求头,对照本文第一节的写法,看有没有 Cache-Control: max-age=0、If-None-Match、If-Modified-Since,再看状态码是 304 还是 200。

3. 再做一次强制重新加载,同样找到这条请求,看请求头里是不是换成了 Cache-Control: no-cache 和 Pragma: no-cache,状态码是不是 200。

4. 把两次的请求头和状态码分别记下来,对照第四节和第五节的说明核对。

需要提醒的是,你看到的字段组合可能因为浏览器不同而有差异。文档已经说明 Safari 的请求看起来会有点不同,所以不要把某一次观察到的结果当成所有浏览器的固定写法。

观看知识要点视频 18 秒

18秒无旁白要点导览,文字来自已审核正文;完整步骤、条件及参考资料见下方。

参考资料

以下原始资料提供本文依据;请结合日期、适用条件和产品说明查阅。

请结合原始资料的适用条件阅读。

返回浏览器工具 →