Cache-Control中no-cache和must-revalidate有什么区别?

230

根据RFC 2616:

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1

no-cache

如果no-cache指令没有指定字段名,则缓存必须在与源服务器进行成功重新验证之前,不得使用响应以满足后续请求。这允许源服务器防止即使已配置为向客户端请求返回陈旧响应的缓存也进行缓存。

因此,它指导代理程序重新验证所有响应。

与此相比:

  

must-revalidate

     

当缓存收到包含must-revalidate指示的响应时,该缓存在将其失效后不能用来响应后续请求,而不是首先通过重新验证将其与源服务器重新验证。

因此,它指导代理程序重新验证旧响应。

特别是关于no-cache,用户代理实际上是否以经验为依据处理此指令?

如果有must-revalidatemax-age,那么no-cache有什么意义?

请参阅此评论:

http://palpapers.plynt.com/issues/2008Jul/cache-control-attributes/

  

no-cache

     

尽管此指令听起来像是在指示浏览器不要缓存页面,但这是一个微妙的区别。根据RFC,"no-cache"指令告诉浏览器应该在从缓存中提供页面之前与服务器重新验证。重新验证是一种机制,可让缓存在相同时间内返回新数据而无需在每个请求上都去检查源服务器。

这是一种巧妙的技术,可以让应用程序节省带宽。如果浏览器缓存的页面没有更改,服务器会向浏览器发送信号,页面将从缓存中显示。因此,浏览器(至少在理论上)将页面存储在其缓存中,但仅在与服务器重新验证后才显示该页面。实际上,IE和Firefox已经开始将no-cache指令视为指示浏览器甚至不要缓存页面。我们大约一年前开始观察到这种行为。我们怀疑这种变化是由于广泛(并且不正确)使用此指令来防止缓存而引起的。

有人有更正式的信息吗?

更新

必须重新验证指令只有在不验证表示时请求可能导致错误操作(例如静默未执行的金融交易)时,服务器才应使用。

直到现在我才真正认真对待这件事。RFC是说不要轻易使用must-revalidate。问题是,在Web服务中,您必须采取负面视角,并为未知的客户端应用程序假定最坏的情况。任何过时的资源都有可能引起问题。

我刚才考虑了另一件事,在没有Last-Modified或ETags的情况下,浏览器只能再次获取整个资源。但是,使用ETags,我观察到至少Chrome似乎在每个请求上重新验证。这使得这两个指令毫无意义,或者至少命名不当,因为除非请求还包括其他标头,否则它们无法正确重新验证。

我只想让最后一点更清楚。只需设置must-revalidate,但不包括ETag或Last-Modified,代理程序只能再次获取内容,因为它没有任何东西发送到服务器进行比较。

然而,我的实证测试表明,当响应中包含ETag或modified标头数据时,代理程序始终重新验证,而不管是否存在must-revalidate标头。

因此,must-revalidate 的目的是在缓存失效时强制执行“绕过缓存”,这只有在设置了生命周期/年龄时才会发生。因此,如果在没有年龄或其他标头的响应上设置了must-revalidate,那么它实际上变成等效于no-cache,因为响应将立即被视为过期。-- 因此,我最终会标记Gili的答案!

因此,理论上的区别在于_validate-always_与_validate-if-stale_,而实际上,某些浏览器会将no-cache视为您引用的注释所说的_never-validate_...因此,您应该根据实际想要实现的缓存行为来选择使用哪种。 - CBroe
请阅读以下链接:http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p6-cache-latest.html看看这是否能为您澄清问题。 - Julian Reschke
请查看此决策树以获取答案:https://stackoverflow.com/a/49925190/3748498 - pravdomil
6个回答

244
我认为must-revalidate的意思是:

一旦缓存过期,即使用户说可以接受陈旧的响应,也拒绝返回陈旧的响应。

no-cache则意味着:

must-revalidate加上响应立即变得陈旧的事实。

如果一个响应可缓存10秒,则must-revalidate在10秒后开始起作用,而no-cache则意味着在0秒后就会进行must-revalidate

至少这是我的理解。


2
这就是我现在的看法。有趣的部分是我的最后一段,如果没有 ETag 或 Last-Modified,代理程序就没有任何东西可以用来验证其缓存中的内容,并且必须再次下载整个有效载荷。因此,当 RFC 说“重新验证”时,可能意味着重新获取。 - Luke Puplett
65
这也意味着 max-age=0, must-revalidateno-cache 是相同的。 - Anshul
6
起初我认为你说的 'max-age=0, must-revalidate 和 no-cache 是相同的' 是正确的,但是看到 Jeffrey Fox 的回答似乎表明这并不完全正确。 - Don Hatch
4
不,"must-revalidate" 和 "no-cache" 对于新鲜响应有不同的含义:如果缓存的响应是新鲜的(即响应没有过期),使用 "must-revalidate" 将使代理立即提供它而无需与服务器重新验证,而使用"no-cache" 则表示无论响应是否新鲜,代理都必须重新验证缓存的响应。来源:"HTTP - 权威指南",第 182-183 页。 - Matthias Braun
11
啊,我能看到混淆的源头了。也许我应该写成“no-cachemax-age=0, must-revalidate是相同的”。 - Anshul
显示剩余7条评论

25

max-age=0, must-revalidateno-cache并不完全相同。使用must-revalidate时,如果服务器无法响应重新验证请求,则浏览器/代理应返回504错误。而使用no-cache则只会显示缓存的内容,这可能是用户更喜欢的(宁愿有过时内容也不要没有)。这就是为什么must-revalidate仅用于关键事务。


15
我对于你关于 no-cache 的解释不太确定。根据 RFC 7234 文档,"no-cache" 响应指令表示在没有经过原始服务器成功验证的情况下,不能使用该响应来满足后续请求。这使得原始服务器可以防止缓存在没有联系它的情况下使用它来满足请求,即使是已配置为发送陈旧响应的缓存也是如此。这听起来类似于 must-revalidate 的限制。 - Anshul
15
杰弗里是否有证据表明实现的行为与他所描述的一样? - OrangeDog
1
我认为这个答案对于代理/负载均衡服务器是正确的。但实际上,在这种情况下,浏览器不会返回504。 - Yann Dìnendal
所以 must-validate 意味着 必须刷新 - Simon_Weaver
6
“Cache-Control” HTTP头部字段在 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control 中直接说明了 "no-cache" 和 "max-age=0, must-revalidate" 具有相同的含义。 - jess

20

根据Jeffrey Fox关于no-cache的解释,我在Chrome 52.0.2743.116 m下进行了测试,结果显示no-cachemust-revalidate具有相同的行为,即当服务器不可达时,它们都不会使用本地缓存,而当使用浏览器的“后退/前进”按钮时,它们都会使用缓存。

综上所述,我认为max-age=0, must-revalidate在实现上与no-cache是相同的。


1
当服务器可重新验证时,Chrome是否会使用本地缓存(即“If-Modified-Since”)?在两种情况下都是这样吗? - Rich

4

说实话,MDN 关于 HTTP 验证的页面直接解决了这个问题(重点是我的):

It is often stated that the combination of max-age=0 and must-revalidate has the same meaning as no-cache.

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

max-age=0 means that the response is immediately stale, and must-revalidate means that it must not be reused without revalidation once it is stale — so in combination, the semantics seem to be the same as no-cache.

However, that usage of max-age=0 is a remnant of the fact that many implementations prior to HTTP/1.1 were unable to handle the no-cache directive — and so to deal with that limitation, max-age=0 was used as a workaround.

But now that HTTP/1.1-conformant servers are widely deployed, there's no reason to ever use that max-age=0-and-must-revalidate combination — you should instead just use no-cache.

仅供参考(仅限于我们自己的个人缓存控制,呵呵),该MDN页面的最后更新日期为2022年6月1日;我于2022年6月10日提取了这个引用(归档于6月8日)。


很好的解释,对于我们开发人员来说,忘记旧版本的古老兼容性原因是很典型的...在我们的SlickStack(LEMP)项目中,对于动态内容例如WordPress页面,我们设置nocache但启用服务器端Nginx FastCGI缓存,对于静态文件,我们设置public,max-age = 691200,这也可能被CDN(如Cloudflare)覆盖。 - Jesse Nickles
它说使用其中一个而不是另一个没有理由,但并没有直接说明它们具有相同的行为。特别是,客户端是否会使用“如果修改自”请求有什么区别?我认为这段文字留下了这种可能性。 - Rich
它说“没有理由”优先使用其中一个,但并没有直接说它们的行为完全相同。特别是,关于客户端是否会使用“如果修改自”请求是否有差异,这段文字似乎没有明确回答,但也没有排除这种可能性。 - undefined

0

同意 @Jeffrey Fox 答案的一部分:

max-age=0、must-revalidate 和 no-cache 并不完全相同。

不同意以下部分:

使用 no-cache 时,它只会显示缓存内容,这可能是用户所期望的(有些过时的内容总比没有内容好)。

cache-control: no-cache 的重新验证失败在 RFC 文档中没有具体说明时,实现应该怎么做就完全取决于实现。他们可以像 cache-control: must-revalidate 一样抛出 504 错误,或者只是从缓存中提供一个旧副本。


-2

我认为max-age=0, must-revalidateno-cache之间存在差异:

must-revalidate的情况下,客户端允许发送If-Modified-Since请求,并且如果返回304 Not Modified,则可以从缓存中提供响应。

no-cache的情况下,客户端不应缓存响应,因此不应使用If-Modified-Since


9
但是 no-cache 并不意味着 no-store - 使用 no-cache,客户端仍然可以缓存资源;只不过在使用之前必须重新验证该资源。 - Aron
7
你将no-cacheno-store混淆了。no-cache的意思是资源必须要进行重新验证重新验证包括使用条件请求的选项,例如If-None-MatchIf-Modified-Since - Jules Sam. Randolph
1
@JulesRandolph:你可能是对的。你有任何测试/演示吗?这个问题上所有相互矛盾且没有证据支持的断言都让人沮丧。即使被接受的答案只是说“至少,那是我的解释”。如果我有时间,我可能会建立一个测试平台并在这里发布它。 - Rich
我的错误是我自己的问题。 - Michael Rogers

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