“Cache-Control: max-age=0”和“no-cache”有什么区别?

730

头部信息Cache-Control: max-age=0表示内容立即被认为是过时的(必须重新获取), 实际上与Cache-Control: no-cache是同样的效果。


4
当用户访问网站时,浏览器需要下载并加载页面的各种资源,如图片、样式表和JavaScript文件。HTTP缓存可以通过让浏览器在本地存储这些资源来提高性能,并在未发生更改时从本地加载它们,而不是每次都从服务器下载它们。本文介绍了如何使用HTTP缓存来优化网站性能,包括缓存指令、实体标签和缓存控制响应头字段等。 - FindOut_Quran
9个回答

675

我曾经有同样的问题,并且在我的搜索中找到了一些信息(你的问题是搜索结果之一)。这是我得出的结论...

Cache-Control标头有两个方面。一个方面是可以由Web服务器(即“原始服务器”)发送的地方,另一个方面是可以由浏览器(即“用户代理”)发送的地方。


当由原始服务器发送时

我认为max-age=0仅仅告诉缓存(和用户代理),响应从一开始就已过时,因此它们SHOULD在使用缓存副本之前重新验证响应(例如使用If-Not-Modified标头),而no-cache则告诉它们MUST在使用缓存副本之前重新验证。 从14.9.1 可缓存性是什么:

no-cache

... 缓存必须不使用响应来满足后续请求,除非与原始服务器进行成功重新验证。这允许原始服务器防止甚至被配置为返回过时响应的缓存缓存。

换句话说,缓存有时可能选择使用旧的响应(尽管我认为它们必须添加一个Warning标头),但是no-cache表示无论如何都不允许使用旧的响应。也许当在页面中生成棒球统计数据时,您希望采用SHOULD-重新验证行为,但是当您生成电子商务购买的响应时,则希望采用MUST-重新验证行为。

尽管您的评论是正确的,即 no-cache 不应该防止存储,但使用 no-cache 可能会有另一种区别。我发现了一个名为“缓存控制指令解密”的页面(我无法保证其正确性),链接为:https://web.archive.org/web/20140811162719/http://palizine.plynt.com/issues/2008Jul/cache-control-attributes/,它说道:

实际上,IE 和 Firefox 已经开始将 no-cache 指令视为指示浏览器甚至不缓存该页面。我们大约在一年前开始观察到这种行为。我们怀疑这种变化是由于广泛(且不正确)地使用该指令来防止缓存所导致的。

...

请注意,最近,“cache-control: no-cache”也开始像“no-store”指令一样运作。

另外,对我而言,Cache-Control: max-age=0, must-revalidate 基本上应该与 Cache-Control: no-cache 意思相同。因此,这可能是一种获得 MUST-revalidate 行为的方法,同时避免 no-cache 看起来像 no-store(即完全不缓存)的行为。
当由用户代理发送时:
我认为shahkalpesh的回答适用于用户代理端。您还可以查看13.2.6 Disambiguating Multiple Responses。如果用户代理发送一个带有Cache-Control: max-age=0的请求(也称为“端到端重新验证”),那么沿途的每个缓存都会重新验证其缓存条目(例如使用If-Not-Modified头)直到源服务器。如果回复是304(未修改),则可以使用缓存实体。
另一方面,发送一个带有Cache-Control: no-cache的请求(也称为“端到端重新加载”)不会重新验证,并且服务器不能在响应时使用缓存副本。

10
Cache-Control: max-age=0, must-revalidate, proxy-revalidate与no-cache是否完全等效? - Didier A.
1
很好的答案,我去看了你引用的文章,但是页面已经不存在了。http://palisade.plynt.com/issues/2008Jul/cache-control-attributes/ - Craig London
9
谢谢,@CraigLondon。我将其重定向到缓存版本。 - Michael Krebs
6
must-revalidate 不等同于 no-cacheno-storeno-cacheno-store 都会直接绕过缓存,但是 must-revalidate 只是说明缓存必须始终检查是否为最新资源,如果是最新的,可以使用该缓存,从而节省带宽。而 no-cacheno-store 则强制每次都要完全下载资源,浪费带宽并延迟响应时间。 - Patanjali
8
“no-cache”并不会完全“绕过缓存”或者“始终强制进行端到端的完整下载”,至少在所有浏览器中都不是这样。根据规范,浏览器只需要验证缓存即可。 - Franklin Yu
显示剩余10条评论

59

max-age=0

等同于点击“刷新”,这意味着除非我已经拥有最新的副本,否则请给我最新的副本。

no-cache

相当于按住 Shift 键并点击“刷新”,这意味着无论如何都重新执行所有操作。


70
这是不正确的。 shift-refresh 是一个硬刷新,更类似于 no-store - Michael
4
在Firefox 45.0中验证,像Chrome 49.0.2623.87 m一样,当使用Shift+刷新时,也会发送“Pragma: no-cache”。 - Cees Timmerman
2
你的描述不准确。这会误导人们。 - jKlaus

37

虽然这是一个旧问题,但如果有其他人像我一样通过搜索遇到这个问题,则似乎IE9将使用此功能来配置在使用后退和前进按钮时资源的行为。当使用max-age=0时,浏览器将在按下后退/前进时使用资源的最新版本。如果使用no-cache,则会重新获取资源。

有关IE9缓存的更多详细信息,请参见msdn缓存博客文章


4
同样地,当使用no-cache和https时,IE 8会遇到各种“无法下载”的问题。建议解决方法有时包括将头部更改为max-age=0。 - Robert Christ

31

在我最近对IE8和Firefox 3.5的测试中,两者似乎都符合RFC标准。然而,它们在对源服务器的“友好度”方面存在差异。IE8将no-cache响应与max-age=0,must-revalidate具有相同的语义。然而,Firefox 3.5似乎将no-cache视为等同于no-store,这会影响性能和带宽利用率。

默认情况下,Squid Cache似乎永远不会存储任何具有no-cache头的内容,就像Firefox一样。

我的建议是对于非敏感资源,您希望每次请求时都检查其新鲜度,但仍允许缓存的性能和带宽优势,请设置public,max-age=0。对于具有相同考虑因素的每个用户项目,请使用private,max-age=0

我建议完全避免使用no-cache,因为它似乎已被某些浏览器和流行的缓存混淆为等效于no-store

此外,请不要模仿Akamai和Limelight。尽管它们基本上将大规模缓存阵列作为主要业务,并且应该是专家,但它们实际上有利益驱动,希望从其网络中下载更多数据。Google也可能不是一个好的仿效选择。他们似乎根据资源的不同随机使用max-age=0no-cache


3
密码保护内容的最佳答案是 private,max-age=0 - dana

23
max-age 当中间缓存通过max-age=0指示强制重新验证自己的缓存条目,并且客户端在请求中提供了自己的验证器时,提供的验证器可能与当前存储在缓存条目中的验证器不同。在这种情况下,缓存可以使用任一验证器进行自己的请求,而不影响语义透明性。
然而,验证器的选择可能会影响性能。最好的方法是中间缓存在进行其请求时使用自己的验证器。如果服务器回复304(未修改),则缓存可以使用200(OK)响应将其已经验证的副本返回给客户端。但是,如果服务器回复新实体和缓存验证器,则中间缓存可以使用强比较函数将返回的验证器与客户端请求中提供的验证器进行比较。如果客户端的验证器等于源服务器的验证器,则中间缓存只需返回304(未修改)。否则,它将使用200(OK)响应返回新实体。
如果请求包括no-cache指令,则不应包括min-fresh、max-stale或max-age。

来源:http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4

请勿将此作为答案接受 - 我需要阅读以理解其真正的用途 :)


我实际上尝试阅读了那个页面,但是并没有理解它。我来到stackoverflow希望得到一个简单、清晰的答案。 - Florian F

16
我虽然不是缓存专家,但 Mark Nottingham 是。这里是他的缓存文档。他在参考文献部分还有很棒的链接。
根据我阅读这些文档的经验,max-age=0 可能会允许缓存将缓存响应发送给在“同一时间”到达的请求,其中“同一时间”指的是它们接近同时到达缓存,但 no-cache 不会这样做。

很好的观点,但在实践中,任何浏览器都真正做到了吗? - Pacerier
4
我认为这更适用于如Varnish、Squid、Traffic等缓存代理服务器。 - Hank Gay

15

值得一提的是,部分移动设备,特别是像iPhone/iPad等苹果产品,完全忽略诸如 no-cache、no-store、Expires: 0 等头信息,无论你试图强制其不重用已过期的表单页面。

这给我们带来了很多麻烦,因为当用户的iPad(比如)处于休眠状态时,它们可能会停留在一个通过表单处理到达的页面上,比如第2步/3步,然后设备完全忽略了存储/缓存指令,并按照我所知道的,简单地从其最后状态中获取虚拟快照,即忽略了明确告知的内容,而且获取了一个不应该被存储的页面,并且没有实际检查它再次获取,这会导致各种奇怪的Session问题,还有其他问题。

我只是添加了这个内容,以防有人遇到不能理解为什么他们在使用iPhone和iPad时会出现会话错误的情况,它们似乎是这方面最糟糕的罪犯。

我对这个问题进行了相当广泛的调试测试,我的结论是,这些设备完全忽略这些指令。

即便在日常使用中,我发现一些移动设备也完全无法通过诸如Expires:0,然后检查修改日期来决定是否应该获取新版本。

这根本不会发生,因此我被迫添加了查询字符串到我需要强制更新的css/js文件中,这欺骗那些愚蠢的移动设备,使它们认为这是一个未被获取的文件,例如:my.css?v=1,然后采用?v=2进行css/js更新。这在很大程度上起作用。

顺便提一句,如果用户浏览器使用默认设置, 我发现截至2016年(我们对网站进行了大量更改和更新),它们也会忽略此类文件的最后修改日期。但是查询字符串方法可以解决这个问题。我注意到客户和办公人员通常使用浏览器的基本默认设置,对于css/js等缓存问题毫无意识,几乎总是不能在更改时获取新的css/js。这意味着,他们的浏览器默认情况下,主要是MSIE/Firefox,没有按照指示执行其任务,它们忽略更改、忽略最后修改日期,并且不进行验证,即使明确设置了Expires:0。

这是一个内容充实的好帖子,包含很多优秀的技术信息,但重要的是要注意移动设备对此类支持有多么糟糕。每隔几个月,我都必须添加更多保护层,以防它们不能遵循接收到的标头命令或正确解释这些命令。


CSS和JS是适合缓存的候选项,因为在生产系统中它们不应该经常更改。然而,在开发过程中为它们设置缓存会很麻烦,因为这可能需要频繁强制清除缓存。但是,如果不能为不同的环境使用不同的设置,则生产要求应优先考虑,因为相对于少数开发人员需要进行的几次Ctrl-F5刷新,大量访问将节省带宽。然而,查询实时数据要求缓存控制正常工作。 - Patanjali

6

这个问题在MDN关于缓存控制的文档中有直接的回答:

Most HTTP/1.0 caches don't support no-cache directives, so historically max-age=0 was used as a workaround. But only max-age=0 could cause a stale response to be reused when caches disconnected from the origin server. must-revalidate addresses that. That's why the example below is equivalent to no-cache.

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

But for now, you can simply use no-cache instead.

另外在 MDN 关于验证缓存的文档 中也有说明:

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.


1
希望您不介意增加的文档。我发现了一个重复的问题(似乎是),我先找到了它,然后我写了一个几乎完全相同的[答案](https://dev59.com/jWMl5IYBdhLWcg3wwZPc#72575381)(伟大的思想...)。但是后来我发现了这个问题并看到了您的答案,所以我想扩展您的答案,而不是再发布另一个答案。我认为这是一个有用的补充,但如果您想回滚,也没关系。 - Jason C

2

有一件(令人惊讶的)事情还没有被提及,那就是请求可以明确指示它将接受过期数据,使用max-stale指令。在这种情况下,如果服务器响应了max-age=0,缓存只会认为响应已经过期,并且可以自由地使用它来满足客户端的请求[该请求要求可能过期的数据]。相比之下,如果服务器发送no-cache,那么它真正地打败了客户端(带有max-stale)对过期数据的任何请求,因为缓存必须重新验证。


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