哪些是适用于内容可变的最佳缓存相关HTTP头?

5
我们有几个文件通过HTTP服务,这些文件不时地改变。为了优化浏览器加载速度,同时强制浏览器验证它是否拥有该文件的最新版本,应返回哪些与缓存相关的HTTP头信息?
目前,我们已经设置了一个“过期”头信息,其日期在过去(这一点似乎已经形成共识)。
但是,有些人建议设置以下头信息:
Cache-Control: no-cache, no-store, must-revalidate

这个头部的问题在于它防止浏览器保留文件的本地副本,因此每次都会下载文件,即使文件没有变化且返回码为200。如果只是使用下面的代码:
Cache-Control: no-cache

然后浏览器(至少 Firefox 14 和 Chrome 20)会保留本地副本,发送 If-Modified-SinceIf-None-Match 头部信息,服务器返回 304 状态码,文件内容不会被下载。 这是针对那些可能随时更改的文件的最佳行为。

问题在于,我不知道仅设置“no-cache”是否足以强制所有浏览器(包括旧版本但仍在使用的版本)和代理服务器与服务端重新验证其本地缓存的副本。

最后,Pragma: no-cache头部信息怎么样? 它也应该包含在 HTTP 响应中吗?


如果您有答案,应该编写自己的答案并将其标记为答案,而不是在问题中添加粗体语句。 - Alexis Wilke
@AlexisWilke 这个粗体语句并不是我的问题的答案,只是我想要强调的一些内容。 - Óscar
3个回答

6
谷歌开发者文档中有一份关于缓存的良好文档,并提供了一些不错的使用模式。
例如,它有一个流程图来定义最佳的缓存控制策略。

enter image description here

此外,它定义了一种很好的模式,可以为文件添加指纹并设置更长时间的过期时间,例如一年。

  • 本地缓存响应将被使用,直到资源“过期”
  • 在URL中嵌入文件内容指纹使我们能够强制客户端更新响应的新版本
  • 每个应用程序都需要定义自己的缓存层次结构以实现最佳性能

enter image description here


定义每个资源的缓存策略使我们能够定义“缓存层次结构”,从而不仅可以控制每个资源的缓存时间,还可以控制访问者看到新版本的速度。例如,让我们分析上面的示例:
- HTML 标记为“no-cache”,这意味着浏览器将始终在每个请求上重新验证文档,并在内容更改时获取最新版本。此外,在 HTML 标记中,我们在 CSS 和 JavaScript 资产的 URL 中嵌入指纹:如果这些文件的内容发生变化,则页面的 HTML 也会发生变化,并且将下载 HTML 响应的新副本。 - 浏览器和中间缓存(例如 CDN)允许缓存 CSS,并设置为 1 年后过期。请注意,我们可以安全地使用 1 年的“远期过期”时间,因为我们在文件名中嵌入了文件指纹:如果更新了 CSS,则 URL 也会更改。 - JavaScript 也设置为 1 年后过期,但被标记为私有,可能是因为它包含一些 CDN 不应该缓存的私有用户数据。 - 图像没有版本或唯一指纹进行缓存,并在 1 天后过期。
ETag、Cache-Control 和唯一的 URL 的组合使我们能够提供最佳的所有选择:长期的到期时间,对响应可以缓存的位置的控制以及按需更新。

谷歌的另一份文档与此相矛盾。在这个文档中,他们建议对于可能随时更改的内容使用Cache-Control: public, max-age=0, must-revalidate而不是Cache-Control: no-cache - Óscar
请注意,在 Firefox 中,ETag 可能会导致“问题”,因为它似乎一直重新检查数据,即使您的缓存持续时间大于零。 因此,版本化的文件(如 CSS 和 JS 文件)不应使用 ETag - Alexis Wilke

1

也许最好的方式,虽然可能不完全符合您的需求是:

Cache-Control:max-age=315360000, public
Expires:Tue, 23 Aug 2022 10:53:13 GMT

给文件起一个“内容相关的文件名”,例如stylesheet_v32.css。 一旦内容发生变化,更改文件名+引用,浏览器就会获取最新版本。如果文件名不变,浏览器就不需要请求它。

这是安全和一致的浏览器操作。

依赖于Cache-Control: no-cache和浏览器仍然保存它是我不想做的事情。


0

我找到了两种方法来强制客户端重新检查缓存:

Cache-Control: max-age=0, must-revalidate
Expires: Thu, 01 Jan 1970 00:00:00 GMT

这适用于至少Firefox。我想IE和Chrome也会正确地响应。它应该可以在使用HTTP/1.0的旧浏览器中工作。

使用HTTP 1.1,您可以使用ETag。在这种情况下,must-revalidate选项是不必要的,因为拥有ETag足以使客户端像must-revalidate一样响应:

Cache-Control: max-age=0
ETag: 123
Expires: Thu, 01 Jan 1970 00:00:00 GMT

这将告诉客户端使用 ETag 123 创建数据的缓存版本,并在每次需要该数据的副本时重新检查服务器。然后,您可以回复 304 Not Modified

绝对不能使用的两个选项是:no-cacheno-store

如果您想防止中间缓存缓存数据,请确保将 private 添加到 Cache-Control 选项中。

作为有趣的特性,您还可以使用短暂的最大时间(例如几分钟)来让客户端缓存该数据,然后发送一个 GET 请求,您可以用 304 来回答:

Cache-Control: max-age=300
ETag: 123
Expires: Tue, 29 Mar 2015 15:05:00 GMT

在这种情况下,浏览器预计在5分钟内不会检查新数据。之后,它会发送给您If-None-Match: 123

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接