Service Worker 缓存和 HTTP 缓存

跨 Service Worker 缓存和 HTTP 缓存层使用一致或不同的到期逻辑的优缺点。

虽然 Service Worker 和 PWA 成为现代 Web 应用的标准,但资源缓存比以往任何时候都更加复杂。本文将介绍浏览器缓存的整体概况,包括:

  • 服务工件缓存和 HTTP 缓存的用例及区别。
  • 与常规 HTTP 缓存策略相比,不同服务工件缓存过期策略的优缺点。

缓存流程概览

概括来讲,浏览器在请求资源时会遵循以下缓存顺序:

  1. Service Worker 缓存:Service Worker 检查资源是否在缓存中,并根据其编程缓存策略决定是否返回资源本身。请注意,此过程不会自动执行。您需要在服务工作线程中创建一个提取事件处理脚本并拦截网络请求,以便请求从服务工作线程的缓存(而非网络)提供。
  2. HTTP 缓存(也称为浏览器缓存):如果在 HTTP 缓存中找到资源且该资源尚未过期,浏览器会自动使用 HTTP 缓存中的资源。
  3. 服务器端:如果服务工作器缓存或 HTTP 缓存中没有找到任何内容,浏览器会转到网络请求资源。如果资源未缓存在 CDN 中,请求必须一直返回到源服务器。

缓存流程

缓存层

Service Worker 缓存

服务工作器会拦截网络类型的 HTTP 请求,并使用缓存策略来确定应将哪些资源返回给浏览器。Service Worker 缓存和 HTTP 缓存具有相同的用途,但 Service Worker 缓存提供更多缓存功能,例如精确控制缓存的内容以及缓存的执行方式。

控制 Service Worker 缓存

服务工件使用事件监听器(通常是 fetch 事件)拦截 HTTP 请求。此代码段演示了缓存优先缓存策略的逻辑。

显示服务工如何拦截 HTTP 请求的图

强烈建议使用 Workbox,以免重复造轮子。例如,您可以使用一行正则表达式代码注册资源网址路径

import {registerRoute} from 'workbox-routing';

registerRoute(new RegExp('styles/.*\\.css'), callbackHandler);

服务工件缓存策略和用例

下表概述了常见的 Service Worker 缓存策略以及每种策略的适用情况。

策略 新鲜度理由 用例
仅限网络 内容必须始终保持最新。
  • 付款和结账
  • 对账单
网络回退到缓存 最好提供新内容。不过,如果网络故障或不稳定,则可以提供稍旧的内容。
  • 及时的数据
  • 价格和费率(需要免责声明)
  • 订单状态
重新验证时过时 您可以立即提供缓存的内容,但今后应使用更新后的缓存内容。
  • 新闻 Feed
  • 商品详情页面
  • 消息
先缓存,然后回退到网络 内容为非关键内容,可以从缓存中传送以提高性能,但 Service Worker 应偶尔检查更新。
  • 应用 Shell
  • 常用资源
仅缓存 内容很少会发生变化。
  • 静态内容

Service Worker 缓存的其他优势

除了对缓存逻辑进行精细控制之外,服务工件缓存还提供以下功能:

  • 为源站提供更多内存和存储空间:浏览器会按源站分配 HTTP 缓存资源。换句话说,如果您有多个子网域,它们都共享相同的 HTTP 缓存。我们无法保证您的源/网域的内容会在 HTTP 缓存中保留很长时间。例如,用户可通过在浏览器的设置界面中手动清除或触发网页上的硬重新加载来清除缓存。使用 Service Worker 缓存后,缓存的内容更有可能保持缓存状态。如需了解详情,请参阅永久性存储
  • 在网络不稳定或离线体验方面更灵活:使用 HTTP 缓存时,您只能做出二元选择:缓存资源或不缓存资源。借助服务工件缓存,您可以更轻松地缓解小问题(使用“在重新验证时使用过时数据”策略),提供完整的离线体验(使用“仅缓存”策略),甚至介于两者之间的体验,例如自定义界面,其中页面的某些部分来自服务工件缓存,而某些部分在适当情况下被排除(使用“设置捕获处理脚本”策略)。

HTTP 缓存

浏览器首次加载网页和相关资源时,会将这些资源存储在其 HTTP 缓存中。除非最终用户明确停用,否则浏览器通常会自动启用 HTTP 缓存。

使用 HTTP 缓存意味着依赖服务器来确定何时缓存资源以及缓存多长时间。

使用 HTTP 响应标头控制 HTTP 缓存过期

当服务器响应浏览器对资源的请求时,服务器会使用 HTTP 响应标头告知浏览器应将资源缓存多长时间。如需了解详情,请参阅响应标头:配置 Web 服务器

HTTP 缓存策略和用例

HTTP 缓存比 Service Worker 缓存简单得多,因为 HTTP 缓存仅处理基于时间 (TTL) 的资源过期逻辑。如需详细了解 HTTP 缓存策略,请参阅您应使用哪些响应标头值?摘要

设计缓存到期逻辑

本部分介绍了在服务工件缓存层和 HTTP 缓存层中使用一致的失效逻辑的利弊,以及在这些层中使用单独的失效逻辑的利弊。

以下 Glitch 演示了服务工作器缓存和 HTTP 缓存在不同场景中的实际运作方式:

所有缓存层均采用一致的过期逻辑

为了说明优缺点,我们将从 3 个方面来分析:长期、中期和短期。

场景 长期缓存 中期缓存 短期缓存
Service Worker 缓存策略 缓存、回退到网络 Stale-while-revalidate 网络回退到缓存
服务工件缓存 TTL 30 天 1 天 10 分钟
HTTP 缓存 max-age 30 天 1 天 10 分钟

场景:长期缓存(缓存,回退到网络)

  • 缓存的资源有效(不超过 30 天)时:服务工作器会立即返回缓存的资源,而无需访问网络。
  • 缓存的资源过期(> 30 天):Service Worker 访问网络以提取资源。浏览器的 HTTP 缓存中没有该资源的副本,因此它会在服务器端获取该资源。

缺点:在这种情况下,HTTP 缓存的价值较低,因为当 Service Worker 中的缓存过期时,浏览器始终会将请求传递到服务器端。

场景:中期缓存(Stale-while-revalidate)

  • 缓存的资源有效(小于等于 1 天)时:服务工作器会立即返回缓存的资源,并转到网络提取资源。浏览器的 HTTP 缓存中有该资源的副本,因此将该副本返回给 Service Worker。
  • 缓存的资源已过期(超过 1 天):服务工作器会立即返回缓存的资源,并转到网络提取资源。浏览器的 HTTP 缓存中没有资源的副本,因此它会转到服务器端提取资源。

缺点:Service Worker 需要额外的缓存无效化来替换 HTTP 缓存,以便充分利用“重新验证”步骤。

场景:短期缓存(网络回退到缓存)

  • 当缓存的资源有效(小于等于 10 分钟)时:服务工作器会转到网络提取资源。浏览器的 HTTP 缓存中包含该资源的副本,因此它会将该副本返回给服务工作器,而无需访问服务器端。
  • 缓存的资源过期(> 10 分钟):Service Worker 立即返回缓存的资源,并访问网络以提取资源。浏览器的 HTTP 缓存中没有资源的副本,因此它会在服务器端提取资源。

缺点:与中期缓存场景类似,Service Worker 需要额外的缓存破坏逻辑来替换 HTTP 缓存,以便从服务器端提取最新资源。

在所有场景中使用服务工件

在所有情况下,当网络不稳定时,Service Worker 缓存仍可返回缓存的资源。另一方面,当网络不稳定或宕机时,HTTP 缓存不可靠。

Service Worker 缓存和 HTTP 层采用不同的缓存过期时间逻辑

为了说明利弊,我们将再次从长期、中期和短期三个方面来看待。

场景 长期缓存 中期缓存 短期缓存
Service Worker 缓存策略 缓存、回退到网络 Stale-while-revalidate 网络回退到缓存
服务工件缓存 TTL 90 天 30 天 1 天
HTTP 缓存 max-age 30 天 1 天 10 分钟

场景:长期缓存(缓存,回退到网络)

  • 当缓存的资源在 Service Worker 缓存中有效(小于等于 90 天)时:Service Worker 会立即返回缓存的资源。
  • 当缓存的资源在服务工作器缓存中过期(超过 90 天)时:服务工作器会转到网络提取资源。浏览器的 HTTP 缓存中没有资源的副本,因此它会转到服务器端。

Pros and cons:

  • 优点:由于服务工件会立即返回缓存的资源,因此用户可以获得即时响应。
  • 优点:服务工件可以更精细地控制何时使用其缓存以及何时请求资源的新版本。
  • 缺点:需要制定明确的 Service Worker 缓存策略。

场景:中期缓存(Stale-while-revalidate)

  • 当缓存的资源在服务工作器缓存中有效(小于等于 30 天)时:服务工作器会立即返回缓存的资源。
  • 当 Service Worker 缓存中的缓存资源过期(> 30 天)时:Service Worker 会访问网络以获取该资源。浏览器的 HTTP 缓存中没有资源的副本,因此它会转到服务器端。

Pros and cons:

  • 优点:由于服务工件会立即返回缓存的资源,因此用户可以获得即时响应。
  • 优点:由于“在后台”进行的重新验证,Service Worker 可以确保给定网址的 next 请求使用来自网络的全新响应。
  • 缺点:需要明确定义的 Service Worker 缓存策略。

场景:短期缓存(网络回退到缓存)

  • 当缓存的资源在服务工作器缓存中有效(小于等于 1 天)时:服务工作器会访问网络以获取资源。如果 HTTP 缓存中存在资源,浏览器会返回该资源。如果网络连接中断,Service Worker 会从 Service Worker 缓存中返回资源
  • 当 Service Worker 缓存中的缓存资源过期(> 1 天)时:Service Worker 访问网络以提取资源。由于 HTTP 缓存中的缓存版本已过期,浏览器会通过网络提取资源。

Pros and cons:

  • 优点:当网络不稳定或出现故障时,Service Worker 会立即返回缓存的资源。
  • 缺点:Service Worker 需要额外的缓存破坏机制来替换 HTTP 缓存并发出“优先使用网络”请求。

总结

鉴于缓存场景组合的复杂性,我们不可能设计出涵盖所有情况的一项规则。不过,根据前面部分的发现,在设计缓存策略时,您可以参考以下几点建议:

  • 服务工件缓存逻辑无需与 HTTP 缓存过期逻辑保持一致。如果可能,请在服务工件中使用更长的失效逻辑,以便为服务工件授予更多控制权。
  • HTTP 缓存仍然发挥着重要作用,但在网络不稳定或宕机时,它并不可靠。
  • 重新审视每个资源的缓存策略,确保您的服务工件缓存策略能够发挥作用,且不会与 HTTP 缓存冲突。

了解详情