Visual LabINTERACTIVE LEARNING
计算机基础精校教程

浏览器缓存机制

沿一次真实请求梳理强缓存、协商缓存、ETag 与现代静态资源策略。

Cache-ControlETagHTTP
进阶预计 12 分钟查看源文 ↗

https://www.cnblogs.com/chenhuichao/p/14325953.html

这是一份基于您提供的文章所整理的浏览器缓存机制详细指南。浏览器缓存主要分为“强缓存”和“协商缓存”,合理利用它们可以显著减少数据传输、减轻服务器负担并提升网页加载速度。


浏览器缓存的基本流程

当浏览器第一次请求资源(如 HTML、CSS、JS)时,服务器会在 HTTP 的 Response Header(响应头) 中返回缓存规则。浏览器会将这些资源及其对应的缓存规则存入本地的“缓存数据库”中。再次请求该资源时,浏览器会根据规则决定是直接读取本地缓存,还是向服务器发起验证。


核心机制一:强缓存 (Strong Cache)

强缓存的逻辑非常简单粗暴:只要本地资源没有过期,就直接从本地磁盘或内存中读取,绝对不向服务器发送请求

如何判断是否命中强缓存?

主要通过 Response Header 中的 Cache-Control 字段来判断(以前使用的 Expires 字段已基本淘汰):

  • max-age=xxx:(最重要)规定了资源在 xxx 秒内有效。在这段时间内再次请求,直接使用本地缓存。
  • no-cache:(最重要)不使用强缓存,每次请求都必须直接进入下一步的“协商缓存”阶段。
  • no-store:既不使用强缓存,也不使用协商缓存,每次都向服务器请求最新的完整资源(实际业务中较少使用)。
  • private / public:规定是仅浏览器可以缓存,还是浏览器和代理服务器都可以缓存(前端开发一般无需深究)。

强缓存流程:

  1. 请求资源时,检查 Cache-Control 是否有 max-age
  2. 如果存在且时间未过期,直接读取本地缓存(状态码通常显示 200,并提示来自 disk cache 或 memory cache)。
  3. 如果 max-age 已过期,或者值为 no-cache,则进入协商缓存阶段。

核心机制二:协商缓存 (Negotiated Cache)

当强缓存失效(max-age 过期)或被明确禁用(no-cache)时,协商缓存就会触发。此时,浏览器必须向服务器发送一次 HTTP 请求,来“协商”本地的旧缓存是否还能继续使用。

协商的依据(两对标识):

服务器在初次返回资源时,会在 Response Header 中带上以下两个标识:

  1. ETag:文件的唯一标识符(类似于文件的 MD5 值,内容一变它就变)。
  2. Last-Modified:文件的最后修改时间。

协商缓存流程:

  1. 浏览器再次请求资源时,会在 Request Header 中将之前保存的标识带给服务器,但字段名会发生变化:

    • ETag 变成 If-None-Match
    • Last-Modified 变成 If-Modified-Since
  2. 服务器接收到这两个字段后,与服务器上最新资源的标识进行对比。

  3. 结果 A(资源未更改):服务器返回状态码 304 Not Modified。因为资源没变,所以此时不返回 Body 数据,响应体积极小,浏览器直接去本地读取旧缓存。

  4. 结果 B(资源已更改):服务器返回状态码 200 OK,并在 Body 中带回最新的资源数据和最新的 ETag / Last-Modified 供浏览器下次缓存。


深入细节:为什么有了 Last-Modified 还需要 ETag?

HTTP 1.1 引入 ETag 主要是为了弥补 Last-Modified 的几个致命缺陷:

  1. 修改频繁度不够Last-Modified 的时间粒度只能精确到。如果一个文件在 1 秒内被修改了多次,时间戳察觉不到,会导致浏览器使用错误的老缓存。
  2. 内容没变但时间变了:有时文件只是被重新生成,内容毫无变化,但修改时间更新了。此时如果不看 ETag,服务器会误以为资源更新了,从而返回完整的 200 数据,造成带宽浪费。
  3. 时间获取不精确:某些服务器无法精确获取文件的最后修改时间。

用户行为对缓存的干预

用户在浏览器中的刷新操作,会直接影响缓存策略的执行:

  • 普通刷新 (F5):跳过强缓存规则(直接视为过期),强制向服务器发起协商缓存验证。
  • 强制刷新 (Ctrl+F5):跳过所有缓存规则(强缓存和协商缓存全都不走),表现得就像第一次访问一样,重新从服务器获取所有完整资源。

现代项目的最佳缓存策略(以 Vue 等 SPA 单页应用为例)

在现代前端工程化项目中(如 Vue/React),代码打包工具(如 Webpack/Vite)通常会为静态资源(JS、CSS、图片)的的文件名加上哈希值(如 app.3f8a9b.js)。

基于这种特性,最佳实践如下:

  • 静态资源(JS/CSS/图片):因为内容一旦改变,文件名(hash)就会变,因此可以给这些文件设置长达一年的强缓存 (Cache-Control: max-age=31536000)
  • 入口文件(index.html:这是整个应用的入口,内部引入了带有 hash 的 JS/CSS。如果 HTML 被缓存,用户就会一直访问旧版本的资源链接。因此,需要在 Nginx 或服务器层面,将 index.html 配置为 Cache-Control: no-storeno-cache,确保用户每次都能拉取到最新的入口文件。