概览

HTTP 缓存会存储与恳求相关的呼应,并将存储的呼应复用于后续恳求。

可复用性有几个长处。首要,由于不需求将恳求传递到源服务器,因而客户端和缓存越近,呼应速度就越快。最典型的例子是浏览器自身为浏览器恳求存储缓存。

此外,当呼应可复用时,源服务器不需求处理恳求——由于它不需求解析和路由恳求、依据 cookie 康复会话、查询数据库以获取成果或渲染模板引擎。这减少了服务器上的负载。

缓存的正确操刁难体系的稳定运转至关重要。

不同品种的缓存

HTTP Caching 标准中,有两种不同类型的缓存:私有缓存同享缓存

私有缓存

私有缓存是绑定到特定客户端的缓存——一般是浏览器缓存。由于存储的呼应不与其他客户端同享,因而私有缓存能够存储该用户的个性化呼应。

另一方面,假如个性化内容存储在私有缓存以外的缓存中,那么其他用户或许能够检索到这些内容——这或许会导致无意的信息走漏。

假如呼应包括个性化内容而且你只想将呼应存储在私有缓存中,则有必要指定 private 指令。

Cache-Control: private

个性化内容一般由 cookie 操控,但 cookie 的存在并不能标明它是私有的,因而独自的 cookie 不会使呼应成为私有的。

请留意,假如呼应具有 Authorization 标头,则不能将其存储在私有缓存(或同享缓存,除非 Cache-Control 指定的是 public)中。

同享缓存

同享缓存位于客户端和服务器之间,能够存储能在用户之间同享的呼应。同享缓存能够进一步细分为署理缓存保管缓存

署理缓存

除了访问操控的功能外,一些署理还完结了缓存以减少网络流量。这一般不由服务开发人员办理,因而有必要由恰当的 HTTP 标头等操控。可是,在过去,过期的署理缓存完结——例如没有正确了解 HTTP 缓存标准的完结——经常给开发人员带来问题。

Kitchen-sink 标头如下所示,用于测验处理不了解当时 HTTP 缓存标准指令(如 no-store)的“旧且未更新的署理缓存”的完结。

Cache-Control: no-store, no-cache, max-age=0, must-revalidate, proxy-revalidate

可是,近年来,跟着 HTTPS 变得越来越遍及,客户端/服务器通信变得加密,在许多状况下,途径中的署理缓存只能传输呼应而不能充任缓存。因而,在这种状况下,无需忧虑甚至无法看到呼应的过期署理缓存的完结。

另一方面,假如 TLS 桥接署理经过在 PC 上安装来自组织办理的 CA 证书,以中心人办法解密一切通信,并履行访问操控等,则能够查看呼应的内容并将其缓存。可是,由于证书透明度(certificate transparency)在最近几年变得很遍及,而且一些浏览器只答应运用证书签署时刻戳(signed certificate timestamp)颁布的证书,因而这种办法需求应用于企业战略。在这样的受控环境中,无需忧虑署理缓存“已过期且未更新”。

保管缓存

保管缓存由服务开发人员清晰布置,以降低源服务器负载并有效地交付内容。示例包括反向署理、CDN 和 service worker 与缓存 API 的组合。

保管缓存的特性因布置的产品而异。在大多数状况下,你能够经过 Cache-Control 标头和你自己的配置文件或仪表板来操控缓存的行为。

例如,HTTP 缓存标准本质上没有界说显式删去缓存的办法——可是运用保管缓存,能够经过仪表板操作、API 调用、从头启动等实时删去现已存储的呼应。这答应更自动的缓存战略。

也能够忽略标准 HTTP 缓存标准协议以支撑显式操作。例如,能够指定以下内容以挑选退出私有缓存或署理缓存,一起运用你自己的战略仅在保管缓存中进行缓存。

Cache-Control: no-store

例如,Varnish Cache 运用 VCL(Varnish Configuration Language,一种 DSL逻辑来处理缓存存储,而 service worker 结合缓存 API 答应你在 JavaScript 中创建该逻辑。

这意味着假如保管缓存成心忽略 no-store 指令,则无需将其视为“不契合”标准。你应该做的是,避免运用 kitchen-sink 标头,但请仔细阅读你正在运用的任何保管缓存机制的文档,并确保你挑选的办法能够正确的操控缓存。

请留意,某些 CDN 供给自己的标头,这些标头仅对该 CDN 有效(例如,Surrogate-Control)。目前,正在尽力界说一个 CDN-Cache-Control 标头来标准化这些标头。

跟我一起探索 HTTP-HTTP缓存

启发式缓存

HTTP 旨在尽或许多地缓存,因而即便没有给出 Cache-Control,假如满意某些条件,呼应也会被存储和重用。这称为启发式缓存

例如,采纳以下呼应。此回复最后一次更新是在 1 年前。

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Date: Tue, 22 Feb 2022 22:22:22 GMT
Last-Modified: Tue, 22 Feb 2021 22:22:22 GMT
​
<!doctype html>

试探性地知道,整整一年没有更新的内容在那之后的一段时刻内不会更新。因而,客户端存储此呼应(虽然短少 max-age)偏重用它一段时刻。复用多长时刻取决于完结,但标准主张存储后大约 10%(在本例中为 0.1 年)的时刻。

启发式缓存是在 Cache-Control 被广泛选用之前呈现的一种处理办法,基本上一切呼应都应清晰指定 Cache-Control 标头。

依据 age 的缓存战略

存储的 HTTP 呼应有两种状况:freshstalefresh 状况一般表示呼应依然有效,能够重复运用,而 stale 状况表示缓存的呼应现已过期。

确认呼应何时是 fresh 的和何时是 stale 的标准是 age。在 HTTP 中,age 是自呼应生成以来经过的时刻。这类似于其他缓存机制中的 TTL

以下面的示例呼应为例(604800 秒是一周):

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Date: Tue, 22 Feb 2022 22:22:22 GMT
Cache-Control: max-age=604800
​
<!doctype html>

存储示例呼应的缓存会计算呼应生成后经过的时刻,并将成果用作呼应的 age

关于该示例的呼应,max-age 的意义如下:

  • 假如呼应的 age 小于一周,则呼应为 fresh
  • 假如呼应的 age 超过一周,则呼应为 stale

只要存储的呼应坚持新鲜(fresh),它将用于完结客户端恳求。

当呼应存储在同享缓存中时,有必要通知客户端呼应的 age。继续看示例,假如同享缓存将呼应存储了一天,则同享缓存将向后续客户端恳求发送以下呼应。

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Date: Tue, 22 Feb 2022 22:22:22 GMT
Cache-Control: max-age=604800
Age: 86400
​
<!doctype html>

收到该呼应的客户端会发现它在剩下的 518400 秒内是新鲜(fresh)的,这是呼应的 max-ageAge 之间的差异。

Expires 或 max-age

在 HTTP/1.0 中,新鲜度过去由 Expires 标头指定。

Expires 标头运用清晰的时刻而不是经过指定经过的时刻来指定缓存的生命周期。

Expires: Tue, 28 Feb 2022 22:22:22 GMT

可是时刻格局难以解析,也发现了很多完结的错误,有或许经过成心偏移体系时钟来诱发问题;因而,在 HTTP/1.1 中,Cache-Control 选用了 max-age——用于指定经过的时刻。

假如 ExpiresCache-Control: max-age 都可用,则将 max-age 界说为首选。因而,由于 HTTP/1.1 已被广泛运用,无需特地供给 Expires

Vary 呼应

区别呼应的办法本质上是依据它们的 URL:

跟我一起探索 HTTP-HTTP缓存

可是呼应的内容并不总是相同的,即便它们具有相同的 URL。特别是在履行内容洽谈时,来自服务器的呼应或许取决于 AcceptAccept-LanguageAccept-Encoding 恳求标头的值。

例如,关于带有 Accept-Language: en 标头并已缓存的英语内容,不期望再对具有 Accept-Language: ja 恳求标头的恳求重用该缓存呼应。在这种状况下,你能够经过在 Vary 标头的值中增加“Accept-Language”,依据言语独自缓存呼应。

Vary: Accept-Language

这会导致缓存依据呼应 URLAccept-Language恳求标头的组合进行键控——而不是仅仅依据呼应 URL。

跟我一起探索 HTTP-HTTP缓存

此外,假如你依据用户署理供给内容优化(例如,呼应式规划),你或许会想在 Vary 标头的值中包括“User-Agent”。可是,User-Agent 恳求标头一般具有十分多的变体,这大大降低了缓存被重用的机会。因而,假如或许,请考虑一种依据特征检测而不是依据 User-Agent 恳求标头来改动行为的办法。

关于运用 cookie 来避免其他人重复运用缓存的个性化内容的应用程序,你应该指定 Cache-Control: private 而不是为 Vary 指定 cookie。

验证呼应

过期的呼应不会立即被丢弃。HTTP 有一种机制,能够经过问询源服务器将陈腐的呼应转换为新的呼应。这称为验证,有时也称为从头验证

验证是经过运用包括 If-Modified-SinceIf-None-Match 恳求标头的条件恳求完结的。

If-Modified-Since

以下呼应在 22:22:22 生成,max-age 为 1 小时,因而你知道它在 23:22:22 之前是新鲜的。

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Date: Tue, 22 Feb 2022 22:22:22 GMT
Last-Modified: Tue, 22 Feb 2022 22:00:00 GMT
Cache-Control: max-age=3600
<!doctype html>

到 23:22:22 时,呼应会过期而且不能重用缓存。因而,下面的恳求显现客户端发送带有 If-Modified-Since 恳求标头的恳求,以问询服务器自指定时刻以来是否有任何的改动。

GET /index.html HTTP/1.1
Host: example.com
Accept: text/html
If-Modified-Since: Tue, 22 Feb 2022 22:00:00 GMT

假如内容自指定时刻以来没有更改,服务器将呼应 304 Not Modified

由于此呼应仅表示“没有改变”,因而没有呼应主体——只有一个状况码——因而传输巨细十分小。

HTTP/1.1 304 Not Modified
Content-Type: text/html
Date: Tue, 22 Feb 2022 23:22:22 GMT
Last-Modified: Tue, 22 Feb 2022 22:00:00 GMT
Cache-Control: max-age=3600

收到该呼应后,客户端将存储的陈腐呼应康复为新鲜的,并能够在剩下的 1 小时内重复运用它。

服务器能够从操作体系的文件体系中获取修正时刻,这关于供给静态文件的状况来说是比较简略做到的。可是,也存在一些问题;例如,时刻格局复杂且难以解析,分布式服务器难以同步文件更新时刻。

为了处理这些问题,ETag 呼应标头被标准化作为代替计划。

ETag/If-None-Match

ETag 呼应标头的值是服务器生成的恣意值。服务器关于生成值没有任何约束,因而服务器能够依据他们挑选的任何办法自由设置值——例如主体内容的哈希或版别号。

举个例子,假如 ETag 标头运用了 hash 值,index.html 资源的 hash 值是 deadbeef,呼应如下:

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Date: Tue, 22 Feb 2022 22:22:22 GMT
ETag: "deadbeef"
Cache-Control: max-age=3600
<!doctype html>

假如该呼应是陈腐的,则客户端获取缓存呼应的 ETag 呼应标头的值,并将其放入 If-None-Match 恳求标头中,以问询服务器资源是否已被修正:

GET /index.html HTTP/1.1
Host: example.com
Accept: text/html
If-None-Match: "deadbeef"

假如服务器为恳求的资源确认的 ETag 标头的值与恳求中的 If-None-Match 值相同,则服务器将回来 304 Not Modified

可是,假如服务器确认恳求的资源现在应该具有不同的 ETag 值,则服务器将其改为 200 OK 和资源的最新版别进行呼应。

补白: 在评估如何运用 ETagLast-Modified 时,请考虑以下几点:在缓存从头验证期间,假如 ETagLast-Modified 都存在,则 ETag 优先。因而,假如你只考虑缓存,你或许会以为 Last-Modified 是不必要的。可是,Last-Modified 不仅仅对缓存有用;相反,它是一个标准的 HTTP 标头,内容办理 (CMS) 体系也运用它来显现上次修正时刻,由爬虫调整爬取频率,以及用于其他各种目的。所以考虑到整个 HTTP 生态体系,最好一起供给 ETagLast-Modified

强制从头验证

假如你不期望重复运用呼应,而是期望一直从服务器获取最新内容,则能够运用 no-cache 指令强制验证。

经过在呼应中增加 Cache-Control: no-cache 以及 Last-ModifiedETag——如下所示——假如恳求的资源已更新,客户端将收到 200 OK 呼应,不然,假如恳求的资源没有更新,则会收到 304 Not Modified 呼应。

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Date: Tue, 22 Feb 2022 22:22:22 GMT
Last-Modified: Tue, 22 Feb 2022 22:00:00 GMT
ETag: deadbeef
Cache-Control: no-cache
<!doctype html>

max-age=0must-revalidate 的组合与 no-cache 具有相同的意义。

Cache-Control: max-age=0, must-revalidate

max-age=0 意味着呼应立即过期,而 must-revalidate 意味着一旦过期就不得在没有从头验证的状况下重用它——因而,结合起来,语义好像与 no-cache 相同。

可是,max-age=0 的运用是处理 HTTP/1.1 之前的许多完结无法处理 no-cache 这一指令——因而为了处理这个约束,max-age=0 被用作处理办法。

可是现在契合 HTTP/1.1 的服务器现已广泛布置,没有理由运用 max-age=0must-revalidate 组合——你应该只运用 no-cache

不运用缓存

no-cache 指令不会阻止呼应的存储,而是阻止在没有从头验证的状况下重用呼应。

假如你不期望将呼应存储在任何缓存中,请运用 no-store

Cache-Control: no-store

可是,一般来说,实践中“不缓存”的原因满意以下状况:

  • 出于隐私原因,不期望特定客户以外的任何人存储呼应。
  • 期望一直供给最新信息。
  • 不知道在过期的完结中会产生什么。

在这种状况下,no-store 并不总是最适宜的指令。

以下部分更详细地介绍了这些状况。

不与其他用户同享

假如具有个性化内容的呼应意外地对缓存的其他用户可见,那将是有问题的。

在这种状况下,运用 private 指令将导致个性化呼应仅与特定客户端一同存储,而不会走漏给缓存的任何其他用户。

Cache-Control: private

在这种状况下,即便设置了 no-store,也有必要设置 private

每次都供给最新的内容

no-store 指令阻止存储呼应,但不会删去相同 URL 的任何已存储呼应。

换句话说,假如现已为特定 URL 存储了旧呼应,则回来 no-store 不会阻止旧呼应被重用。

可是,no-cache 指令将强制客户端在重用任何存储的呼应之前发送验证恳求。

Cache-Control: no-cache

假如服务端不支撑条件恳求,你能够强制客户端每次都访问服务端,总是得到最新的 200 OK 呼应。

兼容过期的完结

作为忽略 no-store 的过期完结的处理办法,你或许会看到运用了诸如以下内容的 kitchen-sink 标头:

Cache-Control: no-store, no-cache, max-age=0, must-revalidate, proxy-revalidate

推荐运用 no-cache 作为处理这种过期的完结的代替计划,假如从一开端就设置 no-cache 就没问题,由于服务器总是会收到恳求。

假如你关怀的是同享缓存,你能够经过增加 private 来避免意外缓存:

Cache-Control: no-cache, private

no-store 丢失了什么

你或许以为增加 no-store 是挑选退出缓存的正确办法。

可是,不主张随意授予 no-store,由于你失掉了 HTTP 和浏览器所具有的许多优势,包括浏览器的撤退/前进缓存。

因而,要取得 Web 平台的全部功能集的优势,最好将 no-cacheprivate 结合运用。

从头加载和强制从头加载

能够对恳求和呼应履行验证。

从头加载强制从头加载操作是从浏览器端履行验证的常见示例。

从头加载

为了从页面错误中康复或更新到最新版别的资源,浏览器为用户供给了从头加载功能。

在浏览器从头加载期间发送的 HTTP 恳求的简化视图如下所示:

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

恳求中的 max-age=0 指令指定“重用 age 为 0 或更少的呼应”——因而,中心存储的呼应不会被重用。

恳求经过 If-None-MatchIf-Modified-Since 进行验证。

该行为也在 Fetch 标准中界说,而且能够经过在缓存形式设置为 no-cache 的状况下,在 JavaScript 中调用 fetch() 来重现(留意 reload 不是这种状况下的正确形式):

// 留意:“reload”不是正常从头加载的正确形式;“no-cache”才是
fetch("/", { cache: "no-cache" });

强制从头加载

出于向后兼容的原因,浏览器在从头加载期间运用 max-age=0——由于在 HTTP/1.1 之前的许多过期的完结中不了解 no-cache。可是在这个用例中,no-cache 已被支撑,而且强制从头加载是绕过缓存呼应的另一种办法。

浏览器强制从头加载期间的 HTTP 恳求如下所示:

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

由于这不是带有 no-cache 的条件恳求,因而你能够确认你会从源服务器取得 200 OK

该行为也在 Fetch 标准中界说,而且能够经过在缓存形式设置为 reload 的状况下,在 JavaScript 中调用 fetch() 来重现(留意它不是 force-reload):

// 留意:“reload”——而不是“no-cache”——是“强制从头加载”的正确形式
fetch("/", { cache: "reload" });

避免从头验证

永久不会改动的内容应该被赋予一个较长的 max-age,办法是运用缓存损坏——也就是说,在恳求 URL 中包括版别号、哈希值等。

可是,当用户从头加载时,即便服务器知道内容是不可变的,也会发送从头验证恳求。

为了避免这种状况,immutable 指令可用于清晰指示不需求从头验证,由于内容永久不会改动。

Cache-Control: max-age=31536000, immutable

这能够避免在从头加载期间进行不必要的从头验证。

删去存储的呼应

基本上没有办法删去用很长的 max-age 存储的呼应。

幻想一下,来自 https://example.com/ 的以下呼应已被存储。

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Cache-Control: max-age=31536000
<!doctype html>

一旦呼应在服务器上过期,你或许期望掩盖该呼应,可是一旦存储呼应,服务器就无法履行任何操作——由于由于缓存,不再有恳求抵达服务器。

标准中说到的办法之一是运用不安全的办法(例如 POST)发送对同一 URL 的恳求,但关于许多客户端而言,一般很难成心这样做。

还有一个 Clear-Site-Data: cache 标头和值的标准,但并非一切浏览器都支撑它——即便运用它,它也只会影响浏览器缓存,而不会影响中心缓存。

因而,除非用户手动履行从头加载、强制从头加载或清除历史操作,不然应该假定任何存储的呼应都将保存其 max-age 期间。

缓存减少了对服务器的访问,这意味着服务器失掉了对该 URL 的操控。假如服务器不想失掉对 URL 的操控——例如,在资源被频频更新的状况下——你应该增加 no-cache,以便服务器一直接收恳求并发送预期的呼应。

恳求折叠

同享缓存首要位于源服务器之前,旨在减少到源服务器的流量。

因而,假如多个相同的恳求一起抵达同享缓存,中心缓存将代表自己将单个恳求转发到源,然后源能够将成果重用于一切客户端。这称为恳求折叠

当恳求一起抵达时会产生恳求折叠,因而即便呼应中给出了 max-age=0no-cache,它也会被重用。

假如呼应是针对特定用户个性化的,而且你不期望它在折叠中同享,则应增加 private 指令:

跟我一起探索 HTTP-HTTP缓存

常见的缓存形式

Cache-Control 标准中有很多指令,或许很难全部了解。可是大多数网站都能够经过几种形式的组合来掩盖。

本节介绍规划缓存的常见形式。

默许设置

如上所述,缓存的默许行为(即关于没有 Cache-Control 的呼应)不是简略的“不缓存”,而是依据所谓的“启发式缓存”进行隐式缓存。

为了避免这种启发式缓存,最好显式地为一切呼应供给一个默许的 Cache-Control 标头。

为确保默许状况下一直传输最新版别的资源,一般的做法是让默许的 Cache-Control 值包括 no-cache

Cache-Control: no-cache

另外,假如服务完结了 cookie 或其他登录办法,而且内容是为每个用户个性化的,那么也有必要供给 private,以避免与其他用户同享:

Cache-Control: no-cache, private

缓存损坏

最适合缓存的资源是静态不可变文件,其内容永久不会改动。而关于会改变的资源,一般的最佳实践是每次内容改变时都改动 URL,这样 URL 单元能够被缓存更长的时刻。

例如,考虑以下 HTML

<script src="bundle.js"></script>
<link rel="stylesheet" href="build.css" />
<body>
  hello
</body>

在现代 Web 开发中,JavaScript 和 CSS 资源会跟着开发的进展而频频更新。此外,假如客户端运用的 JavaScript 和 CSS 资源的版别不同步,则显现将中断。

所以上面的 HTML 用 max-age 缓存 bundle.jsbuild.css 变得很困难。

因而,你能够运用包括依据版别号或哈希值的更改部分的 URL 来供给 JavaScript 和 CSS。一些办法如下所示。

# version in filename
bundle.v123.js
# version in query
bundle.js?v=123
# hash in filename
bundle.YsAIAAAA-QG4G6kCMAMBAAAAAAAoK.js
# hash in query
bundle.js?v=YsAIAAAA-QG4G6kCMAMBAAAAAAAoK

由于缓存依据它们的 URL 来区别资源,因而假如在更新资源时 URL 产生改变,缓存将不会再次被重用。

<script src="bundle.v123.js"></script>
<link rel="stylesheet" href="build.v123.css" />
<body>
  hello
</body>

经过这种规划,JavaScript 和 CSS 资源都能够被缓存很长时刻。那么 max-age 应该设置多长时刻呢?QPACK 标准供给了该问题的答案。

QPACK 是一种用于压缩 HTTP 标头字段的标准,其间界说了常用字段值表。

一些常用的缓存头值如下所示。

36 cache-control max-age=0
37 cache-control max-age=604800
38 cache-control max-age=2592000
39 cache-control no-cache
40 cache-control no-store
41 cache-control public, max-age=31536000

假如你挑选其间一个编号选项,则能够在经过 HTTP3 传输时将值压缩为 1 个字节。

数字“37”、“38”和“41”别离代表一周、一个月和一年。

由于缓存会在保存新条目时删去旧条目,所以一周后存储的呼应依然存在的或许性并不高——即便 max-age 设置为 1 周。因而,在实践中,你挑选哪一种并没有太大的区别。

请留意,数字“41”具有最长的 max-age(1 年),但具有 public

public 值具有使呼应可存储的效果,即便存在 Authorization 标头。

补白: 只有在设置了 Authorization 标头时需求存储呼应时才应运用 public 指令。不然不需求,由于只要给出了 max-age,呼应就会存储在同享缓存中。

因而,假如呼应是运用基自身份验证进行个性化的,public 的存在或许会导致问题。假如你对此感到担忧,你能够挑选第二长的值 38(1 个月)。

# response for bundle.v123.js
# If you never personalize responses via Authorization
Cache-Control: public, max-age=31536000
# If you can't be certain
Cache-Control: max-age=2592000

验证呼应

不要忘记设置 Last-ModifiedETag 标头,以便在从头加载时不必从头传输资源。关于预构建的静态文件生成这些标头很简略。

这里的 ETag 值或许是文件的哈希值。

# response for bundle.v123.js
Last-Modified: Tue, 22 Feb 2022 20:20:20 GMT
ETag: YsAIAAAA-QG4G6kCMAMBAAAAAAAoK

此外,能够增加 immutable 以避免从头加载时验证。

组合成果如下所示。

# bundle.v123.js
200 OK HTTP/1.1
Content-Type: application/javascript
Content-Length: 1024
Cache-Control: public, max-age=31536000, immutable
Last-Modified: Tue, 22 Feb 2022 20:20:20 GMT
ETag: YsAIAAAA-QG4G6kCMAMBAAAAAAAoK

缓存损坏是一种经过在内容更改时更改 URL 来使呼应在很长一段时刻内可缓存的技能。该技能能够应用于一切子资源,例如图像。

补白: 在评估 immutable 和 QPACK 的运用时:假如你忧虑 immutable 会更改 QPACK 供给的预界说值,请考虑在这种状况下,immutable 部分能够经过将 Cache-Control 值分红两行来独自编码——虽然这取决于特定 QPACK 完结运用的编码算法。

Cache-Control: public, max-age=31536000
Cache-Control: immutable

首要资源

与子资源不同,主资源不能运用缓存损坏,由于它们的 URL 不能像子资源 URL 相同被润饰。

假如存储以下 HTML 自身,即便在服务器端更新内容,也无法显现最新版别。

<script src="bundle.v123.js"></script>
<link rel="stylesheet" href="build.v123.css" />
<body>
  hello
</body>

关于这种状况,no-cache 将是适宜的——而不是 no-store——由于我们不想存储 HTML,而只是期望它一直是最新的。

此外,增加 Last-ModifiedETag 将答应客户端发送条件恳求,假如 HTML 没有更新,则能够回来 304 Not Modified

200 OK HTTP/1.1
Content-Type: text/html
Content-Length: 1024
Cache-Control: no-cache
Last-Modified: Tue, 22 Feb 2022 20:20:20 GMT
ETag: AAPuIbAOdvAGEETbgAAAAAAABAAE

该设置适用于非个性化 HTML,但关于运用 cookie 进行个性化的呼应(例如,在登录后),不要忘记一起指定 private

200 OK HTTP/1.1
Content-Type: text/html
Content-Length: 1024
Cache-Control: no-cache, private
Last-Modified: Tue, 22 Feb 2022 20:20:20 GMT
ETag: AAPuIbAOdvAGEETbgAAAAAAABAAE
Set-Cookie: __Host-SID=AHNtAyt3fvJrUL5g5tnGwER; Secure; Path=/; HttpOnly

favicon.icomanifest.json.well-known 和无法运用缓存损坏更改 URL 的 API 端点也是如此。

大多数 Web 内容都能够经过上述两种形式的组合来掩盖。

有关保管缓存的更多信息

运用前面章节描绘的办法,子资源能够经过缓存损坏来缓存很长时刻,但主资源(一般是 HTML 文档)不能。

缓存首要资源很困难,由于仅运用 HTTP 缓存标准中的标准指令,在服务器上更新内容时无法自动删去缓存内容。

可是,能够经过布置保管缓存(例如 CDN 或 service worker)来完结。

例如,答应经过 API 或仪表板操作清除缓存的 CDN 将经过存储首要资源并仅在服务器上产生更新时显式清除相关缓存来完结更积极的缓存战略。

假如 service worker 能够在服务器上产生更新时删去缓存 API 中的内容,它也能够这样做。