缓存机制

138 阅读6分钟

浏览器缓存机制是浏览器为了提升页面加载速度、减少网络请求而对资源(如 HTML、CSS、JS、图片等)进行本地存储的技术。它通过合理的缓存策略,让重复访问的资源直接从本地读取,而非重新从服务器获取,从而优化用户体验和减轻服务器压力。

一、缓存的核心目标

  1. 减少网络请求:避免重复下载相同资源,降低带宽消耗。
  2. 提升加载速度:本地读取资源比网络请求快得多(毫秒级 vs 秒级)。
  3. 离线可用:部分缓存策略支持离线访问(如 Service Worker)。

二、缓存的分类与存储位置

浏览器缓存按存储位置和生命周期可分为以下几类:

1. Memory Cache(内存缓存)

  • 存储位置:浏览器内存中。

  • 特点

    • 读写速度最快(内存操作)。
    • 生命周期短:页面关闭后缓存失效(内存释放)。
    • 存储资源:通常是脚本、样式、图片等体积较小的资源。
  • 触发场景:同一页面多次请求相同资源(如同一图片在页面中多次出现)。

2. Disk Cache(磁盘缓存)

  • 存储位置:本地磁盘(硬盘 / SSD)。

  • 特点

    • 读写速度比内存慢,但比网络快。
    • 生命周期长:页面关闭后仍保留,下次打开可复用。
    • 存储资源:体积较大的资源(如大图片、视频片段),或需要长期缓存的资源。
  • 优先级:当内存缓存中没有所需资源时,会检查磁盘缓存。

3. Service Worker Cache(服务工作线程缓存)

  • 存储位置:独立于浏览器进程的本地缓存,需手动控制。

  • 特点

    • 可编程:通过 JS 代码自定义缓存策略(缓存哪些资源、何时更新)。
    • 支持离线访问:是 PWA(渐进式 Web 应用)实现离线功能的核心。
    • 运行在后台:不阻塞主线程,可在页面关闭后继续工作。
  • 触发场景:需开发者主动注册 Service Worker 并编写缓存逻辑(如缓存静态资源供离线使用)。

4. Push Cache(推送缓存)

  • 存储位置:HTTP/2 推送的资源缓存,是浏览器缓存的最后一道防线。

  • 特点

    • 生命周期极短(会话结束后失效)。
    • 仅在 HTTP/2 协议下生效,使用场景有限。

三、缓存策略:从请求到响应的决策流程

浏览器缓存的核心是缓存策略,由服务器通过 HTTP 头字段(Response Headers)控制,决定资源是否缓存、缓存多久、如何验证有效性。

完整的缓存决策流程如下:

  1. 检查强缓存:直接使用本地缓存,不发请求到服务器。
  2. 强缓存失效:检查协商缓存,发送请求到服务器验证资源是否更新。
  3. 协商缓存有效:服务器返回 304(未修改),使用本地缓存。
  4. 协商缓存失效:服务器返回 200 和新资源,更新本地缓存。

1. 强缓存(无需请求服务器)

服务器通过 Expires 或 Cache-Control 头指定资源的有效期,浏览器在有效期内直接使用本地缓存,不与服务器通信。

  • Expires(HTTP/1.0) :格式:Expires: Wed, 26 Oct 2025 12:00:00 GMT(绝对时间)。问题:依赖本地时间,如果客户端时间被修改,可能导致缓存失效或过期资源被使用。

  • Cache-Control(HTTP/1.1,优先级更高) :格式:Cache-Control: max-age=3600(相对时间,单位秒),表示资源在 3600 秒(1 小时)内有效。常用值:

    • max-age=<秒>:资源有效期(核心字段)。
    • no-cache:不使用强缓存,需强制走协商缓存。
    • no-store:完全不缓存(每次都从服务器获取)。
    • public:允许任何缓存(如 CDN)存储该资源。
    • private:仅允许浏览器缓存,不允许中间代理(如 CDN)缓存。

    示例:Cache-Control: public, max-age=86400 表示资源可被公开缓存,有效期 1 天。

2. 协商缓存(需请求服务器验证)

当强缓存失效(资源过期),浏览器会发送请求到服务器,通过 Last-Modified/If-Modified-Since 或 ETag/If-None-Match 验证资源是否更新。若未更新,服务器返回 304,浏览器继续使用本地缓存;若已更新,返回 200 和新资源。

  • Last-Modified 与 If-Modified-Since

    • 服务器响应时返回 Last-Modified: Wed, 25 Oct 2025 10:00:00 GMT(资源最后修改时间)。
    • 浏览器再次请求时,在请求头中携带 If-Modified-Since: Wed, 25 Oct 2025 10:00:00 GMT(上次获取的最后修改时间)。
    • 服务器对比:若资源未修改,返回 304;若已修改,返回 200 和新资源,并更新 Last-Modified
    • 缺点:无法识别秒级以内的修改,或文件内容未变但修改时间变了(会误判为更新)。
  • ETag 与 If-None-Match

    • 服务器响应时返回 ETag: "abc123"(资源内容的唯一标识,如哈希值)。
    • 浏览器再次请求时,在请求头中携带 If-None-Match: "abc123"(上次获取的 ETag 值)。
    • 服务器对比:若 ETag 相同(内容未变),返回 304;若不同(内容已改),返回 200 和新资源,并更新 ETag
    • 优点:基于内容判断,比时间更精准,优先级高于 Last-Modified

四、不同资源的缓存策略建议

根据资源特性(是否常变),需设计不同的缓存策略:

  1. 静态资源(JS、CSS、图片)

    • 特性:不常变,可长期缓存。

    • 策略:

      • 强缓存:Cache-Control: max-age=31536000(1 年)。
      • 配合文件名哈希(如 app.abc123.js):资源更新时,哈希值变化,文件名改变,自动绕过缓存,获取新资源。
  2. HTML 文件

    • 特性:可能包含动态内容(如用户信息),需频繁更新。

    • 策略:

      • 禁用强缓存:Cache-Control: no-cache(强制走协商缓存)。
      • 启用协商缓存:通过 ETag 或 Last-Modified 验证是否更新。
  3. API 接口数据

    • 特性:动态数据,时效性强。

    • 策略:

      • 短期强缓存:Cache-Control: max-age=60(1 分钟,适合非实时数据)。
      • 或禁用缓存:Cache-Control: no-store(如用户余额、实时消息)。
      • 配合 Cache-Control: private(避免敏感数据被代理缓存)。

五、缓存相关的浏览器行为

  • 强制刷新(Ctrl+Shift+R 或 Shift + 刷新按钮) :跳过强缓存和协商缓存,直接从服务器获取最新资源(请求头带 Cache-Control: no-cache)。
  • 普通刷新(F5 或刷新按钮) :跳过强缓存,但会走协商缓存(验证资源是否更新)。
  • 地址栏回车 / 页面跳转:正常遵循缓存策略(先查强缓存,再协商缓存)。

总结

浏览器缓存通过「强缓存(本地直接用)」和「协商缓存(服务器验证)」两层机制,结合不同的存储位置(内存、磁盘、Service Worker),实现了资源的高效复用。合理配置 Cache-ControlETag 等字段,并针对不同资源设计缓存策略,是前端性能优化的核心手段之一。