利用“在重新验证时过时”功能保持内容的新鲜度

一个额外的工具,可帮助您在提供 Web 应用时平衡即时性和新鲜度。

发布了哪些内容?

stale-while-revalidate 可帮助开发者在即时性(立即加载缓存的内容)和新鲜度(确保将来使用缓存内容的更新)之间取得平衡。如果您维护的第三方 Web 服务或库会定期更新,或者您的第一方资源往往具有较短的生命周期,那么 stale-while-revalidate 可能是对现有缓存政策的有用补充。

Chrome 75 和 Firefox 68 支持在 Cache-Control 响应标头中同时设置 stale-while-revalidate 和 max-age。

不支持 stale-while-revalidate 的浏览器会静默忽略该配置值,并使用 max-age,我稍后会对此进行说明…

这是什么意思?

我们将 stale-while-revalidate 分为两部分:缓存的响应可能过时的概念,以及重新验证的过程。

首先,浏览器如何知道缓存的响应是否“过时”?包含 stale-while-revalidate 的 Cache-Control 响应标头还应包含 max-age,通过 max-age 指定的秒数决定了过时性。任何新于 max-age 的缓存响应都会被视为新鲜,而较旧的缓存响应则会过时。

如果本地缓存的响应仍然有效,则可以按原样使用它来满足浏览器的请求。从 stale-while-revalidate 的角度来看,在这种情况下无需执行任何操作。

但如果缓存的响应已过时,则会执行另一项基于时效的检查:缓存的响应的时效是否在 stale-while-revalidate 设置提供的额外时间范围内?

如果过时响应的时长在此时间范围内,则会用于满足浏览器的请求。同时,系统会向网络发出“重新验证”请求,但不会延迟使用缓存的响应。返回的响应可能包含与之前缓存的响应相同的信息,也可能不同。无论哪种情况,网络响应都会存储在本地,替换之前缓存的所有内容,并重置在未来任何 max-age 比较期间使用的“新鲜度”计时器。

但是,如果过时的缓存响应已超出 stale-while-revalidate 时间范围,则不会满足浏览器的请求。浏览器会改为从网络检索响应,并使用该响应来满足初始请求,同时使用新响应填充本地缓存。

实时示例

下面是一个用于返回当前时间(更具体地说是当前分钟数)的 HTTP API 简单示例。

在这种情况下,Web 服务器会在其 HTTP 响应中使用以下 Cache-Control 标头:

Cache-Control: max-age=1, stale-while-revalidate=59

此设置意味着,如果在接下来的 1 秒内重复请求时间,之前缓存的值仍将是新鲜的,并按原样使用,无需任何重新验证。

如果请求在 1 到 60 秒后重复,则缓存的值将过时,但仍会用于满足 API 请求。与此同时,系统会在“后台”发出重新验证请求,以便使用新值填充缓存,供日后使用。

如果请求在超过 60 秒后重复,则根本不会使用过时响应,并且满足浏览器请求和缓存重新验证都将取决于从网络获取响应。

以下是这三种不同状态的细分,以及每种状态在我们的示例中适用的时间范围:

一张图表,展示了上一部分中的信息。

有哪些常见应用场景?

虽然上述“分钟数”API 服务的示例是虚构的,但它说明了预期的用例:服务提供的信息需要刷新,但可以接受一定程度的过时。

更贴近实际的示例可能是用于获取当前天气状况或过去一小时内撰写的头条新闻的 API。

通常,任何以已知间隔更新、可能会被多次请求且在该间隔内保持静态的响应,都适合通过 max-age 进行短期缓存。除了 max-age 之外,使用 stale-while-revalidate 还可以提高未来请求通过缓存中的最新内容得到满足的可能性,而不会阻塞网络响应。

它如何与 Service Worker 交互?

如果您听说过 stale-while-revalidate,那么它很可能是在 Service Worker 中使用的方案。

通过 Cache-Control 标头使用 stale-while-revalidate 与在 Service Worker 中使用它有一些相似之处,并且许多关于新鲜度权衡和最长生命周期的相同注意事项也适用。不过,在决定是实现基于 Service Worker 的方法,还是仅依赖 Cache-Control 标头配置时,您应考虑一些注意事项。

在以下情况下,请使用 Service Worker 方法:

  • 您已在 Web 应用中使用 Service Worker。
  • 您需要对缓存内容进行精细控制,并希望实现类似于最近最少使用过期政策的内容。Workbox 的缓存过期模块可以帮助解决此问题。
  • 您希望在重新验证步骤期间,当过时响应在后台发生更改时收到通知。Workbox 的广播缓存更新模块可以帮助解决此问题。
  • 您需要在所有现代浏览器中实现这种 stale-while-revalidate 行为。

在以下情况下,请使用 Cache-Control 方法:

  • 您不想为 Web 应用部署和维护 Service Worker,因为这会带来额外开销。
  • 您愿意让浏览器的自动缓存管理功能防止本地缓存变得过大。
  • 您愿意采用目前并非所有现代浏览器都支持的方法(截至 2019 年 7 月;未来可能会有更多浏览器支持)。

如果您使用的是 Service Worker,并且还通过 Cache-Control 标头为某些响应启用了 stale-while-revalidate,那么 Service Worker 通常会“优先”响应请求。如果 Service Worker 决定不响应,或者在生成响应的过程中使用 fetch() 发出网络请求,则通过 Cache-Control 标头配置的行为最终会生效。

了解详情