我们的调查表明,并非所有浏览器都以统一的方式遵守HTTP缓存指令。
出于安全原因,我们不希望Web浏览器缓存应用程序中的某些页面。这至少适用于以下浏览器:
- Internet Explorer 6+
- 火狐1.5 +
- 狩猎3号
- 歌剧9 +
- 铬
我们的要求来自安全测试。从我们的网站注销后,您可以按后退按钮并查看缓存页面。
- 就iPad Safari而言,[1]有帮助吗?[1]:stackoverflow.com/questions/24524248/…
- 最简单的方法是:最大年龄=10岁。这并不完美,因为页面将被缓存10秒。但这是最不"头条意大利面"的解决方案。此外,这有时会大大提高使用反向代理的动态网站的性能。(您的慢速PHP脚本将每10秒调用一次,然后由反向代理缓存。每10秒一次比每个访客一次好得多)
- 另请参见securityevaluators.com/knowledge/caseu studies/caching
- 谢谢你提出的这个好问题。出于好奇,什么情况会使您发送一些数据,而不希望接收器出于"安全原因"保存数据。你已经寄了!
- 请参阅stackoverflow.com/a/49925190/3748498
介绍
在所有提到的客户机(和代理)上工作的正确的最小头集:
1 2 3
| Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0 |
Cache-Control符合客户机和代理的HTTP 1.1规范(并且在Expires旁边的一些客户机隐式要求)。Pragma符合用于史前客户机的HTTP 1.0规范。Expires是根据客户机和代理的HTTP1.0和1.1规范提供的。在HTTP 1.1中,Cache-Control优先于Expires,因此它毕竟只适用于HTTP 1.0代理。
如果你不关心IE6和它的坏缓存,而只使用no-store通过https服务页面,那么你可以省略Cache-Control: no-cache。
1 2 3
| Cache-Control: no-store, must-revalidate
Pragma: no-cache
Expires: 0 |
如果您不关心IE6或HTTP1.0客户机(HTTP1.1是1997年推出的),那么可以省略Pragma。
1 2
| Cache-Control: no-store, must-revalidate
Expires: 0 |
如果您也不关心HTTP 1.0代理,那么可以省略Expires。
1
| Cache-Control: no-store, must-revalidate |
另一方面,如果服务器auto包含一个有效的Date头,那么理论上也可以省略Cache-Control,只依赖Expires。
1 2
| Date: Wed, 24 Aug 2016 18:32:02 GMT
Expires: 0 |
但如果最终用户操纵操作系统日期,而客户机软件依赖于操作系统日期,则可能会失败。
如果指定了上述Cache-Control参数,则其他Cache-Control参数(如max-age参数)不相关。这里大多数其他答案中包含的Last-Modified头只有在您实际想要缓存请求时才有意思,因此您根本不需要指定它。
如何设置?
使用PHP:
1 2 3
| header("Cache-Control: no-cache, no-store, must-revalidate"); // HTTP 1.1.
header("Pragma: no-cache"); // HTTP 1.0.
header("Expires: 0"); // Proxies. |
使用JavaServlet或Node.js:
1 2 3
| response.setHeader("Cache-Control","no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma","no-cache"); // HTTP 1.0.
response.setHeader("Expires","0"); // Proxies. |
使用ASP.NET-MVC
1 2 3 4
| Response.Cache.SetCacheability(HttpCacheability.NoCache); // HTTP 1.1.
Response.Cache.AppendCacheExtension("no-store, must-revalidate");
Response.AppendHeader("Pragma","no-cache"); // HTTP 1.0.
Response.AppendHeader("Expires","0"); // Proxies. |
使用ASP.NET Web API:
1 2 3 4 5 6 7 8 9 10 11
| // `response` is an instance of System.Net.Http.HttpResponseMessage
response.Headers.CacheControl = new CacheControlHeaderValue
{
NoCache = true,
NoStore = true,
MustRevalidate = true
};
response.Headers.Pragma.ParseAdd("no-cache");
// We can't use `response.Content.Headers.Expires` directly
// since it allows only `DateTimeOffset?` values.
response.Content?.Headers.TryAddWithoutValidation("Expires", 0.ToString()); |
使用ASP.NET:
1 2 3
| Response.AppendHeader("Cache-Control","no-cache, no-store, must-revalidate"); // HTTP 1.1.
Response.AppendHeader("Pragma","no-cache"); // HTTP 1.0.
Response.AppendHeader("Expires","0"); // Proxies. |
使用ASP:
1 2 3
| Response.addHeader"Cache-Control","no-cache, no-store, must-revalidate" ' HTTP 1.1.
Response.addHeader"Pragma","no-cache" ' HTTP 1.0.
Response.addHeader"Expires","0" ' Proxies. |
使用Ruby on Rails或python/flask:
1 2 3
| headers["Cache-Control"] ="no-cache, no-store, must-revalidate" # HTTP 1.1.
headers["Pragma"] ="no-cache" # HTTP 1.0.
headers["Expires"] ="0" # Proxies. |
使用python/django:
1 2 3
| response["Cache-Control"] ="no-cache, no-store, must-revalidate" # HTTP 1.1.
response["Pragma"] ="no-cache" # HTTP 1.0.
response["Expires"] ="0" # Proxies. |
使用python/pyramid:
1 2 3 4 5 6 7
| request.response.headerlist.extend(
(
('Cache-Control', 'no-cache, no-store, must-revalidate'),
('Pragma', 'no-cache'),
('Expires', '0')
)
) |
使用GO:
1 2 3
| responseWriter.Header().Set("Cache-Control","no-cache, no-store, must-revalidate") // HTTP 1.1.
responseWriter.Header().Set("Pragma","no-cache") // HTTP 1.0.
responseWriter.Header().Set("Expires","0") // Proxies. |
使用apache .htaccess文件:
1 2 3 4 5
| <IfModule mod_headers.c>
Header set Cache-Control"no-cache, no-store, must-revalidate"
Header set Pragma"no-cache"
Header set Expires 0
</IfModule> |
使用HTML4:
1 2 3
| <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" /> |
HTML元标记与HTTP响应头
重要的是要知道,当一个HTML页面通过HTTP连接提供服务,并且在HTTP响应头和HTML 标记中都存在一个头时,HTTP响应头中指定的头将优先于HTML元标记。HTML元标记仅在通过file://URL从本地磁盘文件系统查看页面时使用。另请参见W3 HTML规范第5.2.2章。当您不以编程方式指定它们时,请注意这一点,因为Web服务器也可以包括一些默认值。
一般来说,最好不要指定HTML元标记,以避免初学者混淆,并依赖硬HTTP响应头。此外,特别是那些标签在HTML5中无效。仅允许HTML5规范中列出的http-equiv值。
验证实际的HTTP响应头
要验证其中一个和另一个,可以在WebBrowser开发人员工具集的HTTP流量监视器中查看/调试它们。您可以通过在chrome/firefox23+/ie9+中按F12,然后打开"网络"或"网络"选项卡面板,然后单击感兴趣的HTTP请求来发现有关HTTP请求和响应的所有详细信息。下面的屏幕截图来自Chrome:
我也要在文件下载时设置这些头文件
首先,这个问题和答案的目标是"网页"(HTML页面),而不是"文件下载"(PDF、Zip、Excel等)。最好将它们缓存,并在URI路径或querystring中的某个位置使用某个文件版本标识符,以强制对更改的文件重新下载。当在文件下载中应用那些没有缓存的头文件时,那么在通过HTTPS而不是HTTP提供文件下载服务时要注意IE7/8错误。有关详细信息,请参阅ie cannot download foo.jsf。IE无法打开此Internet站点。请求的站点不可用或找不到。
- 这似乎不完整。我在IE8上尝试了这个解决方案,发现当你点击后退按钮时,浏览器会加载一个缓存版本。
- 很可能你的测试方法是错误的。可能页面已经在缓存中了?也许标题不正确/被重写?也许你看错了要求?等。。
- 这会干扰HTML5清单文件吗?
- @Balusc:有些人告诉我设置Expires为0在某些情况下不起作用,所以最好设置为"过期"。我在php.net上也有一些有趣的评论
- 我想补充一下,我刚刚做了这个,它似乎没有工作,而我正在测试。原来服务器上的IIS正在缓存页面
- 实际上,我确认这种方法是不完整的,并导致IE8出现问题,或者至少在某些情况下。具体来说,当使用IE8通过SSL获取资源时,IE8将拒绝第二次获取资源(无论是完全还是第一次尝试之后,取决于使用的头文件)。例如,参见Ericlaw的博客。
- @Haylem IE6、7和8必须在no-cache之前有no-store,并且不能在https连接上有Pragma头。
- 我想补充一下,这基本上就是美国银行所做的。如果您查看他们的响应头并将其转换为aspx,他们会这样做:response.appendheader("cache control","no cache,no store,must revalidate");response.appendheader("expires","thu,01 dec 1994 16:00:00 gmt");我想,如果它对他们足够好,对我来说就足够好了。
- @约翰:Expires头正好是HTTP1.0规范中的示例值。它是有效的,但是准确地记下时间戳有点荒谬。
- 是的,这是非常武断的,但美国银行使用这个价值!哈哈,我想你用什么并不重要,对吧?但是我发表评论不是为了建议对你的例子进行任何修改,而是为了提供一个现实世界的例子来支持你的例子,这个例子来自我们信任的了解这些东西的人(我们的银行)。
- 您提到的"纯HTML方式"实际上不起作用,即使没有代理;头应该在实际的HTTP头中(例如"expires:0"),而不是在html标记中。当代理挡道时,它保证不会工作:代理依赖于HTTP头,而不是HTML内容。我建议阅读此文档以获得良好的理解:mnot.net/cache_docs
- @卢卡:如答案所述:"只有从本地磁盘文件系统查看页面时,才会使用HTML元标记。"
- 同意,但答案的表述方式令人困惑。"然后,响应头中指定的将优先于HTML元标记。"—当服务于HTTP时,元标记将根本没有任何优先权。此外,代理可能根本无法读取和标记。最后,有些人在找到语法之后就不会再继续阅读了。然后,来自本地文件系统的HTML文件不会改变(除非在开发人员机器上),因此不需要缓存控制,因此使用元缓存控制标记是非常罕见的(我认为附近的一个小注释可以做到)。
- @Haylem你说得对:当用户按下后退按钮时,这个解决方案完全无法强制IE8重新加载页面。不过,考虑到微软提供的文档,这可能是一个IE8错误(在IE9中不会发生),所以我们很难找到解决方案。
- @coredumerror:请注意,Haylem的评论涉及到通过此处回答的IE8下载文件。这与"这个解决方案"进一步无关。
- 这听起来可能是个糟糕的问题。我们是否应该在不想缓存的每个页面中都写这个?如果我在JSP页面中写这个,我应该用meta标记还是使用response.setheader()?
- Raman:不要重复代码,也不要在JSP中编写Java代码。使用过滤器。
- @Balusc,no-cache不是已经暗示must-revalidate了吗?难道no-store已经暗示no-cache了吗?为什么我们不能简单地使用Cache-Control:no-store而不是您在答案中显示的较长版本?
- @你说得对,但浏览器不行。其目的是覆盖所有浏览器,也包括错误的浏览器。
- @Balusc,那么你是建议我们做一些rojak,比如stackoverflow.com/a/49549/632951吗?
- @Balusc,你的解决方案不适用于Safari 5.1.7和Opera
- @基思这是错误的,IE8可以接受通过https的pragma,但不能不接受cache stackoverflow.com/questions/3415370/&hellip;
- @罗伯特克里斯特,我们发现在添加了基于https的Pragmaie6&7时,它必须在no-cache之前有no-store,没有Pragma。由于Pragma只需要IE5和更老版本,所以这是毫无意义的,所以我们没有专门测试IE8。最佳实践可能只是跳过它,因为(除非您支持90年代的浏览器)这只是浪费字节。
- 天哪,我真不敢相信这已经被投票表决了这么多。pragma:no cache"从服务器发送到客户机时没有意义。"no store"不会阻止内存缓存。"只有在从本地磁盘查看页面时才会使用HTML元标记'-也是错误的。请阅读你链接的文件,俾路支
- @symcbean我认为httpbis中的新措辞足够强大,当no-store存在tools.ietf.org/html/&hellip;浏览器可能会将其保留为历史记录,但不应在响应请求时重新提供。
- 实际上,这个列表并不完整。正确的设置为:cache control:无存储,无缓存,必须重新验证,proxy revalidate pragma:无缓存,无存储过期时间:-1上次修改时间:-1
- @chameera:cache-control:proxy revalidate只有在您之前由于一个愚蠢的错误意外地缓存了资源,并且它们在代理中四处游荡时才相关。以后您可以安全地删除它。pragma不支持任何存储,这是特定于缓存控制的。在这种情况下,最后一次修改仍然是不相关的。-1而不是0绝对没有意义,可能会使事情变得更糟。如果你以聪明的方式开始,答案中的列表绝对是完整的。
- @俾路支,你说得对,我在语用上滑倒了。它只支持不缓存,谢谢您的指针。另一方面,任何不想冒险的人都应该使用代理重新验证。另外,如果我没有弄错的话,-1特定于Unix,它将返回可能的最短日期。比过去的某一天硬编码要好得多,imho。
- @Chameera:重新验证代理只是为了修复你自己的错误。从头开始就做!-1是有风险的,因为浏览器可能不需要连字符和/或负日期,并且可能导致整数取消流动(因此您实际上最终得到的是最大日期)。只需遵循当前答案中给出的说明,而不是不必要的捆绑,使其过度复杂。这几乎是荒谬的。
- @hvgotcodes:它似乎干扰了火狐31。我的方法是设置一个较小的最大年龄,例如最大年龄=10。这似乎使AppCache清单在所有浏览器上都能按预期工作。
- "expires"不应该是日期(与"date"标题的值相同),而不是数字"0"?参见mnot.net/cache_docs
- @卢克:无效的格式将被解释为"在过去"。另请参见http header字段规范:"http/1.1客户端和缓存必须处理其他无效的日期格式,尤其是包括值"0",如过去(即"already expired")."。
- 我不能在AmazonS3上定义Pragma: no-cache,你知道为什么吗?没有Pragma: no-cache也能工作吗?
- 不幸的是,W3C验证器将HTML解决方案标记为错误(而不是警告)。必须有一些不会使HTML无效的HTML解决方案…
- @伊沃韦尔奇:在HTML5中,这确实是不允许的。按照答案中的建议使用响应头。
- pragma不是请求头吗?
- @克里斯托夫:从你的链接:"http/1.1客户端和缓存必须处理其他无效的日期格式,特别是包括值"0",如过去(即,"已经过期")(另请参阅我对他的评论的评论回复)。
- @是否每个页面都需要HTTP头,还是只需要索引页?
- 从技术上讲,发送Expires: 0不符合RFC。它表示缓存必须将其解释为"过期",但它不表示允许作为服务器的您为此目的发送格式错误的日期。它甚至建议您发送具有相同值的Expires/Date头,以将其标记为过期。
- 来自Oracle的此页显示"注意:永远不要使用Expires=0来阻止缓存。Expires头由远程服务器发送,并由门户服务器传递给浏览器。除非三台计算机上的时间都同步,否则expires=0头可能会错误地返回缓存的内容。要解决此问题,请将Expires头设置为一个确定为过去的固定日期。这似乎与大多数答案/评论(以及RFC)相矛盾。这是需要考虑的吗?
- 这帮助我在不向get url添加时间戳的情况下调用jquery ajax。
- 请原谅我的无知,这不会只缓存HTML响应,而是允许在CSS/JS上进行更新吗?也就是说,如果HTML有脚本/链接CSS元素,它仍然会得到它们?我不想在每个页面重新加载时重新加载整个bootstrap/jquery
- @首先,它们不是由与HTML页面相同的请求请求请求的。它们是由它们自己的请求请求请求的,当然它们也有自己的响应。
- 这就是我想的,但我想确定一下。特别是因为我可能会在全局过滤的基础上处理它
- 有人能告诉我怎么在Django修这个吗?我所做的一切都不适合狩猎。
(嘿,各位:请不要盲目复制和粘贴所有可以找到的邮件头)
首先,后退按钮历史记录不是缓存:
The freshness model (Section 4.2) does not necessarily apply to history mechanisms. That is, a history mechanism can display a previous representation even if it has expired.
在旧的HTTP规范中,措辞更加强烈,明确地告诉浏览器不要理会后退按钮历史记录的缓存指令。
back应该回到time(用户登录的时间)。它不会向前导航到以前打开的URL。
但是,在实践中,缓存会在非常特殊的情况下影响后退按钮:
- 页面必须通过HTTPS传递,否则此缓存总线将不可靠。另外,如果您不使用HTTPS,那么您的页面很容易被其他许多方式的登录窃取。
- 您必须发送Cache-Control: no-store, must-revalidate(有些浏览器观察no-store,有些浏览器观察must-revalidate)
你永远不需要:
- 带缓存头的-根本不起作用。完全没用。
- post-check/pre-check-这是仅适用于可计算资源的指令。
- 发送同一个标题两次或分十二部分。一些PHP代码片段实际上替换了前面的头,结果只发送了最后一个。
如果需要,可以添加:
- no-cache或max-age=0,这将使资源(url)变得"过时",并要求浏览器在有更新版本的情况下与服务器进行检查(no-store已经暗示这一点更为强大)。
- Expires中有一个HTTP/1.0客户端的日期(尽管目前真正的HTTP/1.0客户端完全不存在)。
额外好处:新的HTTP缓存RFC。
- 在加载时间方面,这会对网站的性能产生任何副作用吗?没有存储,没有缓存,必须重新验证如何影响性能?
- @Ramanghai禁用缓存通常会损害性能(以及您提到的禁用缓存的所有3个选项)。这可能会使cdn和isp代理(如移动运营商常用的代理)失效。它不会影响新用户的第一次加载(除了代理问题),但随后的导航可能会慢很多。
- @你方声明,我方必须向Cache-Control: must-revalidate发送货物。既然no-cache已经暗示must-revalidate,为什么不发送Cache-Control: no-cache?w3.org/protocols/rfc2616/rfc2616-sec14.html sec14.9.1
- @Pacrier对于缓存来说,no-cache与must-revalidate的关系是正确的,但是back history不是缓存。浏览器特殊情况下显式must-revalidate来控制历史行为。
- @Pornel,嗯,有没有一个支持的RFC声明这是期望的行为?
- @Pornel,我刚刚测试了你的解决方案(https+必须重新验证)。它可以在Opera上工作,但不能在Chrome上工作。
正如Pornel所说,您不需要停用缓存,而是停用历史缓冲区。不同的浏览器有自己的微妙方法来禁用历史缓冲区。好的。
在铬(V28.0.1500.95 m)中,我们只能通过Cache-Control: no-store来实现这一点。好的。
在火狐(v23.0.1)中,任何一个都可以工作:好的。
Cache-Control: no-store好的。
Cache-Control: no-cache(仅限https)好的。
Pragma: no-cache(仅限https)好的。
Vary: *(仅限https)好的。
在Opera(v12.15)中,我们只能通过Cache-Control: must-revalidate来实现(仅限https)。好的。
在Safari(v5.1.7,7534.57.2)中,其中任何一个都可以工作:好的。
Cache-Control: no-storeHTML格式的好的。
Cache-Control: no-store(仅限https)好的。
在IE8(V8.0.6001.18702IC)中,其中任何一个都可以工作:好的。
Cache-Control: must-revalidate, max-age=0好的。
Cache-Control: no-cache好的。
Cache-Control: no-store好的。
Cache-Control: must-revalidateExpires: 0好的。
Cache-Control: must-revalidateExpires: Sat, 12 Oct 1991 05:00:00 GMT好的。
Pragma: no-cache(仅限https)好的。
Vary: *(仅限https)好的。
结合以上内容,我们得到了适用于Chrome28、Firefox 23、IE8、Safari 5.1.7和Opera 12.15的解决方案:Cache-Control: no-store, must-revalidate(仅限https)好的。
请注意,需要使用HTTPS,因为Opera不会为纯HTTP页停用历史缓冲区。如果您真的无法获得HTTPS,并且准备忽略Opera,那么最好的方法是:好的。
1 2
| Cache-Control: no-store
<body onunload=""> |
下面显示了我的测试的原始日志:好的。
http:好的。
Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0Expires: 0Pragma: no-cacheVary: *fail:opera 12.15成功:Chrome 28、Firefox 23、IE8、Safari 5.1.7好的。
Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0Expires: Sat, 12 Oct 1991 05:00:00 GMTPragma: no-cacheVary: *fail:opera 12.15成功:Chrome 28、Firefox 23、IE8、Safari 5.1.7好的。
Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0Expires: 0Pragma: no-cacheVary: *fail:safari 5.1.7,opera 12.15成功:Chrome 28、Firefox 23、IE8好的。
Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0Expires: Sat, 12 Oct 1991 05:00:00 GMTPragma: no-cacheVary: *fail:safari 5.1.7,opera 12.15成功:Chrome 28、Firefox 23、IE8好的。
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0Expires: 0Pragma: no-cacheVary: *fail:chrome 28,firefox 23,safari 5.1.7,opera 12.15成功:IE8好的。
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0Expires: Sat, 12 Oct 1991 05:00:00 GMTPragma: no-cacheVary: *fail:chrome 28,firefox 23,safari 5.1.7,opera 12.15成功:IE8好的。
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0Expires: 0Pragma: no-cacheVary: *fail:chrome 28,firefox 23,safari 5.1.7,opera 12.15成功:IE8好的。
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0Expires: Sat, 12 Oct 1991 05:00:00 GMTPragma: no-cacheVary: *fail:chrome 28,firefox 23,safari 5.1.7,opera 12.15成功:IE8好的。
Cache-Control: no-storefail:safari 5.1.7,opera 12.15成功:Chrome 28、Firefox 23、IE8好的。
Cache-Control: no-storefail:opera 12.15成功:Chrome 28、Firefox 23、IE8、Safari 5.1.7好的。
Cache-Control: no-cachefail:chrome 28,firefox 23,safari 5.1.7,opera 12.15成功:IE8好的。
Vary: *fail:chrome 28,firefox 23,ie8,safari 5.1.7,opera 12.15成功:无好的。
Pragma: no-cachefail:chrome 28,firefox 23,ie8,safari 5.1.7,opera 12.15成功:无好的。
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0Expires: Sat, 12 Oct 1991 05:00:00 GMTPragma: no-cacheVary: *fail:chrome 28,firefox 23,safari 5.1.7,opera 12.15成功:IE8好的。
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0Expires: 0Pragma: no-cacheVary: *fail:chrome 28,firefox 23,safari 5.1.7,opera 12.15成功:IE8好的。
Cache-Control: must-revalidate, max-age=0fail:chrome 28,firefox 23,safari 5.1.7,opera 12.15成功:IE8好的。
Cache-Control: must-revalidateExpires: 0fail:chrome 28,firefox 23,safari 5.1.7,opera 12.15成功:IE8好的。
Cache-Control: must-revalidateExpires: Sat, 12 Oct 1991 05:00:00 GMTfail:chrome 28,firefox 23,safari 5.1.7,opera 12.15成功:IE8好的。
Cache-Control: private, must-revalidate, proxy-revalidate, s-maxage=0Pragma: no-cacheVary: *fail:chrome 28,firefox 23,ie8,safari 5.1.7,opera 12.15成功:无好的。
HTTPS:好的。
Cache-Control: private, max-age=0, proxy-revalidate, s-maxage=0Expires: 0fail:chrome 28,firefox 23,ie8,safari 5.1.7,opera 12.15成功:无好的。
Cache-Control: private, max-age=0, proxy-revalidate, s-maxage=0Expires: Sat, 12 Oct 1991 05:00:00 GMTfail:chrome 28,firefox 23,ie8,safari 5.1.7,opera 12.15成功:无好的。
Vary: *fail:chrome 28,safari 5.1.7,opera 12.15成功:火狐23,IE8好的。
Pragma: no-cachefail:chrome 28,safari 5.1.7,opera 12.15成功:火狐23,IE8好的。
Cache-Control: no-cachefail:chrome 28,safari 5.1.7,opera 12.15成功:火狐23,IE8好的。
Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0fail:chrome 28,safari 5.1.7,opera 12.15成功:火狐23,IE8好的。
Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0Expires: 0Pragma: no-cacheVary: *fail:chrome 28,safari 5.1.7,opera 12.15成功:火狐23,IE8好的。
Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0Expires: Sat, 12 Oct 1991 05:00:00 GMTPragma: no-cacheVary: *fail:chrome 28,safari 5.1.7,opera 12.15成功:火狐23,IE8好的。
Cache-Control: must-revalidatefail:chrome 28,firefox 23,ie8,safari 5.1.7成功:歌剧12.15好的。
Cache-Control: private, must-revalidate, proxy-revalidate, s-maxage=0fail:chrome 28,firefox 23,ie8,safari 5.1.7成功:歌剧12.15好的。
Cache-Control: must-revalidate, max-age=0fail:chrome 28,firefox 23,safari 5.1.7成功:IE8,歌剧12.15好的。
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0Expires: Sat, 12 Oct 1991 05:00:00 GMTPragma: no-cacheVary: *fail:chrome 28,safari 5.1.7成功:火狐23、IE8、Opera 12.15好的。
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0Expires: 0Pragma: no-cacheVary: *fail:chrome 28,safari 5.1.7成功:火狐23、IE8、Opera 12.15好的。
Cache-Control: no-storefail:opera 12.15成功:Chrome 28、Firefox 23、IE8、Safari 5.1.7好的。
Cache-Control: private, no-cache, no-store, max-age=0, proxy-revalidate, s-maxage=0Expires: 0Pragma: no-cacheVary: *fail:opera 12.15成功:Chrome 28、Firefox 23、IE8、Safari 5.1.7好的。
Cache-Control: private, no-cache, no-store, max-age=0, proxy-revalidate, s-maxage=0Expires: Sat, 12 Oct 1991 05:00:00 GMTPragma: no-cacheVary: *fail:opera 12.15成功:Chrome 28、Firefox 23、IE8、Safari 5.1.7好的。
Cache-Control: private, no-cacheExpires: Sat, 12 Oct 1991 05:00:00 GMTPragma: no-cacheVary: *fail:chrome 28,safari 5.1.7,opera 12.15成功:火狐23,IE8好的。
Cache-Control: must-revalidateExpires: 0fail:chrome 28,firefox 23,safari 5.1.7,成功:IE8,歌剧12.15好的。
Cache-Control: must-revalidateExpires: Sat, 12 Oct 1991 05:00:00 GMTfail:chrome 28,firefox 23,safari 5.1.7,成功:IE8,歌剧12.15好的。
Cache-Control: private, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0Expires: 0fail:chrome 28,firefox 23,safari 5.1.7,成功:IE8,歌剧12.15好的。
Cache-Control: private, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0Expires: Sat, 12 Oct 1991 05:00:00 GMTfail:chrome 28,firefox 23,safari 5.1.7,成功:IE8,歌剧12.15好的。
Cache-Control: private, must-revalidateExpires: Sat, 12 Oct 1991 05:00:00 GMTPragma: no-cacheVary: *fail:chrome 28,safari 5.1.7成功:火狐23、IE8、Opera 12.15好的。
Cache-Control: no-store, must-revalidatefail:none成功:Chrome 28、Firefox 23、IE8、Safari 5.1.7、Opera 12.15好的。
好啊。
- 我知道这是几年前发布的,但这是一个有趣的阅读。这个问题已经让我疯狂了几个月,身体似乎真的知道如何处理缓存控制。我见过一些人使用,但它更像是解决实际问题的一种方法。我已经尝试过使用.htaccess并以这种方式修改头文件,如果我使用https,它会以这种方式工作吗?问题最严重的地方主要是狩猎。
- @根据上面的日志,如果你有https,那么添加Cache-Control: no-store就可以了。只有在没有https的情况下才需要。
我发现web.config路由很有用(尝试将其添加到答案中,但似乎未被接受,因此在此处发布)
1 2 3 4 5 6 7 8 9 10 11 12 13
| <configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<!-- HTTP 1.1. -->
<!-- HTTP 1.0. -->
<!-- Proxies. -->
</customHeaders>
</httpProtocol>
</system.webServer> |
下面是express/node.js的方法:
1 2 3 4 5 6
| app.use(function(req, res, next) {
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
res.setHeader('Pragma', 'no-cache');
res.setHeader('Expires', '0');
next();
}); |
- 对于web.config,我只需要修改一点,以便仅对那些我们知道是动态加载/使用RequireJS的脚本应用自定义头。假设您的脚本位于客户机文件夹:<位置>
- 对于那些想知道web.conf是什么的人来说:它是ASP.NETWeb应用程序的主要设置和配置文件。它是一个驻留在根目录中的XML文档。(维基)。
我发现这一页上的所有答案都有问题。特别是,我注意到,当您通过点击后退按钮访问该页面时,它们中没有一个会阻止IE8使用该页面的缓存版本。
经过大量的研究和测试,我发现我真正需要的两个头部是:
Cache-Control: no-store
Vary: *
有关vary头的说明,请访问http://www.w3.org/protocols/rfc2616/rfc2616-sec13.html sec13.6。
在IE6-8、FF1.5-3.5、Chrome 2-3、Safari 4和Opera 9-10上,当您单击指向页面的链接或将URL直接放在地址栏中时,这些头会导致从服务器请求页面。截至2010年1月,这覆盖了99%的浏览器。
在IE6和Opera9-10上,点击后退按钮仍然会导致加载缓存版本。在我测试的所有其他浏览器上,它们确实从服务器上获取了一个新版本。到目前为止,我还没有找到任何一组标题,当您单击后退按钮时,这些浏览器不会返回页面的缓存版本。
更新:在写下这个答案之后,我意识到我们的Web服务器将自己标识为一个HTTP1.0服务器。我列出的头是正确的,以便浏览器不缓存来自HTTP 1.0服务器的响应。对于HTTP1.1服务器,请查看Balusc的答案。
- 这适用于IE8的后退按钮!!在尝试了所有其他建议之后,添加"vary:*"标题显然是唯一一个可以强制IE8在用户按下后退按钮时重新加载页面的方法。这在HTTP/1.1服务器上是有效的。
- 结合barlusc建议的头文件,再加上一个JS片段,当onpageShow事件触发"persisted"属性时调用window.location.reload()(对于safari是必需的),当用户使用back按钮时,我测试过的每个浏览器都会成功地从服务器强制重新加载。
- @coredumerror,哦,您不应该假设启用了javascript。
- @克里斯,刚刚测试过。它不适用于Safari 5.1.7和Opera…
- @Pacerier在我2010年写这个答案的时候,它处理了Safari和Opera的最新版本,我们的服务器将自己标识为HTTP1.0服务器。不幸的是,我已经没有任何方法可以轻松地测试这个了,所以我不能对这些浏览器的最新版本说任何明确的东西。
- 您测试的浏览器版本是什么?
- 根据我当时写的,我测试了IE6到8,ff1.5到3.5,chrome 2和3,Safari4,以及Opera9和10。
经过一番研究,我们得出了以下似乎涵盖大多数浏览器的标题列表:
- 有效期至:1997年7月26日周一05:00:00 GMT
- 缓存控制:无缓存,私有,必须重新验证,max stale=0,post check=0,pre check=0,无存储
- pragma:没有缓存
在ASP.NET中,我们使用以下代码段添加了这些代码:
1 2 3 4 5 6 7 8 9 10
| Response.ClearHeaders();
Response.AppendHeader("Cache-Control","no-cache"); //HTTP 1.1
Response.AppendHeader("Cache-Control","private"); // HTTP 1.1
Response.AppendHeader("Cache-Control","no-store"); // HTTP 1.1
Response.AppendHeader("Cache-Control","must-revalidate"); // HTTP 1.1
Response.AppendHeader("Cache-Control","max-stale=0"); // HTTP 1.1
Response.AppendHeader("Cache-Control","post-check=0"); // HTTP 1.1
Response.AppendHeader("Cache-Control","pre-check=0"); // HTTP 1.1
Response.AppendHeader("Pragma","no-cache"); // HTTP 1.0
Response.AppendHeader("Expires","Mon, 26 Jul 1997 05:00:00 GMT"); // HTTP 1.0 |
网址:http://forums.asp.net/t/1013531.aspx
- @巴特:更麻烦的是,1997年7月26日是星期六,而不是星期一……
- Cache-Control: no-cache和Cache-Control: private冲突——你永远不应该两者兼而有之:前者告诉浏览器和代理根本不需要缓存,后者告诉代理不需要缓存,但允许浏览器保存自己的私有副本。我不确定浏览器将遵循哪种设置,但浏览器和版本之间不太可能保持一致。
- @爱德华,测试过,但不在Safari 5.1.7和Opera上工作
- 不要使用预检查和后检查。blogs.msdn.com/b/ieinternals/archive/2009/07/20/&hellip;
- 这对我不起作用-使用ASP.NET 4.5代码运行,但不会产生所需的结果。我必须这样做:stackoverflow.com/questions/22443932/&hellip;
在响应中使用pragma头是一个妻子的故事。RFC2616仅将其定义为请求头
http://www.mnot.net/cache_docs/pragma
- 这是一个很好的例子,说明为什么你需要超越规范。如果规范总是清晰的,那么对于StackOverflow这样的站点来说就没有什么意义了。为了与HTTP 1.0服务器向后兼容,Internet Explorer支持HTTP pragma:no cache头的特殊用法。如果客户端通过安全连接(https://)与服务器通信,并且服务器返回带有响应的pragma:no cache头,则Internet Explorer不会缓存响应。
- @迈克洛克:你的引用是有效的,但错过了更大的一点——设置一个适当的缓存控制/过期,你不需要杂注。
免责声明:我强烈建议阅读@balusc的答案。在阅读了以下缓存教程:http://www.mnot.net/cache_docs/(我建议您也阅读它),我相信它是正确的。但是,出于历史原因(并且因为我自己测试过),我将在下面列出我的原始答案:
我尝试了PHP的"接受"答案,但这对我不起作用。然后我做了一点研究,发现了一个微小的变异,测试了它,它起作用了。这里是:
1 2 3 4 5 6 7
| header('Cache-Control: no-store, private, no-cache, must-revalidate'); // HTTP/1.1
header('Cache-Control: pre-check=0, post-check=0, max-age=0, max-stale = 0', false); // HTTP/1.1
header('Pragma: public');
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header('Expires: 0', false);
header('Last-Modified: '.gmdate('D, d M Y H:i:s') . ' GMT');
header ('Pragma: no-cache'); |
那应该管用。问题是,当两次设置头的同一部分时,如果没有将false作为头函数的第二个参数发送,则头函数将简单地覆盖以前的header()调用。因此,在设置Cache-Control时,例如,如果不想将所有参数都放到一个header()函数调用中,他必须这样做:
1 2
| header('Cache-Control: this');
header('Cache-Control: and, this', false); |
请参阅此处的更多完整文档。
- 这充满了神话。预检查和后检查仅限于IE,仅与缓存响应相关,0值为no-op。max stale是代理请求头,而不是服务器响应头。Expires只接受单个值。多个将导致忽略此头。
- @波内尔,你会提交一份正确处理这些神话的竞争性答案吗?
- @奇怪的是,看起来stackoverflow.com/questions/49547/hellip;是一个有竞争力的答案。
- @史蒂文,刚刚测试过。它不适用于Safari 5.1.7和Opera…
- @是的,正如我在免责声明中所说,使用俾路支的答案。
IE6中有一个错误
即使使用"cache-control:no-cache",也始终缓存带有"content-encoding:gzip"的内容。
http://support.microsoft.com/kb/321722
您可以为IE6用户禁用gzip压缩(检查用户代理中的"msie 6")。
对于ASP.NET核心,创建一个简单的中间件类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class NoCacheMiddleware
{
private readonly RequestDelegate m_next;
public NoCacheMiddleware( RequestDelegate next )
{
m_next = next;
}
public async Task Invoke( HttpContext httpContext )
{
httpContext.Response.OnStarting( ( state ) =>
{
// ref: http://stackoverflow.com/questions/49547/making-sure-a-web-page-is-not-cached-across-all-browsers
httpContext.Response.Headers.Append("Cache-Control","no-cache, no-store, must-revalidate" );
httpContext.Response.Headers.Append("Pragma","no-cache" );
httpContext.Response.Headers.Append("Expires","0" );
return Task.FromResult( 0 );
}, null );
await m_next.Invoke( httpContext );
}
} |
然后在Startup.cs注册
1
| app.UseMiddleware<NoCacheMiddleware>(); |
一定要在后面加上这个
- 我建议使用来自microsoft.net.http.headers.headername的常量,而不是字符串文本"cache controls"、"pragma"和"expires"。
HTTP 1.1的RFC表示,正确的方法是为以下对象添加一个HTTP头:
缓存控制:无缓存
如果旧的浏览器不符合HTTP1.1,它们可能会忽略这一点。对于那些你可以尝试的标题:
pragma:没有缓存
这也应该适用于HTTP 1.1浏览器。
- 规范指出,在没有重新验证的情况下,不能重复使用响应。它是缓存控件:no store,这是一种官方方法,用于指示响应最初甚至没有存储在缓存中。
header函数的PHP文档有一个相当完整的示例(由第三方提供):
1 2 3 4 5 6 7
| header('Pragma: public');
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
header('Last-Modified: '.gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate'); // HTTP/1.1
header('Cache-Control: pre-check=0, post-check=0, max-age=0', false); // HTTP/1.1
header ("Pragma: no-cache");
header("Expires: 0", false); |
- 这显然是错误的。对header()的第二个调用用于expires、cache control和pragma完全覆盖以前设置的值。
- @Pornel:不,不要覆盖以前设置的值,因为他将false作为第二个参数传递,告诉我们不要覆盖以前的值。
- @朱丽叶:我发表评论后,答案被编辑了。这仍然没有什么意义。
- 如果要在9之前的IE中工作,请不要发送多个缓存控制头。不要发送预检查或后检查。blogs.msdn.com/b/ieinternals/archive/2009/07/20/&hellip;
这些指令不能减轻任何安全风险。它们实际上是为了迫使行动单位更新易变信息,而不是阻止行动单位保留信息。看看这个类似的问题。至少,不能保证任何路由器、代理等也不会忽略缓存指令。
更积极的是,有关计算机物理访问、软件安装等方面的政策将使您在安全性方面远远领先于大多数公司。如果这些信息的消费者是公众,你唯一能做的就是帮助他们理解,一旦这些信息击中他们的机器,那机器就是他们的责任,而不是你的责任。
将修改后的HTTP头设置为1995年的某个日期通常可以做到这一点。
下面是一个例子:
1 2 3
| Expires: Wed, 15 Nov 1995 04:58:08 GMT
Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
Cache-Control: no-cache, must-revalidate |
- @安德斯,刚刚测试过。它不适用于Safari 5.1.7和Opera…
- 也不适用于Chrome 40.xx
- 设置一个很久以前最后一次修改对缓存没有影响,除了让缓存的响应由于启发式的重新验证而使用更长时间。
如果您在SSL和缓存上遇到IE6-IE8下载问题:MS Office文件没有缓存头(和类似的值),则可以使用缓存:private,no store header,以及post请求时返回的文件。它起作用了。
在我的例子中,我用这个解决了Chrome的问题
1
| <form id="form1" runat="server" autocomplete="off"> |
当用户出于安全原因单击后退按钮时,我需要清除previus表单数据的内容
- 我的Mozilla 19.x浏览器问题也被代码片段解决了。autocomplete="关闭"。谢谢您。
另外,为了更好地衡量,如果您使用.htaccess文件来启用缓存,请确保您重置了该文件中的ExpiresDefault。
1
| ExpiresDefault"access plus 0 seconds" |
然后,可以使用ExpiresByType为要缓存的文件设置特定值:
1
| ExpiresByType image/x-icon"access plus 3 month" |
如果您的动态文件(如php等)被浏览器缓存,并且您无法找出原因,那么这也会很方便。检查ExpiresDefault。
当使用浏览器的后退按钮时,Balusc提供的答案中的标题不会阻止Safari 5(以及可能更早的版本)显示浏览器缓存中的内容。防止这种情况的一种方法是向body标记添加空的onUnload事件处理程序属性:
这个黑客显然破坏了Safari中的后向缓存:当单击后退按钮时,是否存在跨浏览器的OnLoad事件?
- 很酷,我已经测试过了,这实际上在Safari(5.1.7)上有效,但不是Opera。
- 不使用Safari 10。还有其他建议吗?
通过设置pragma:没有缓存
接受的答案似乎对iis7+不起作用,因为有大量关于ii7中未发送的缓存头的问题:
- 一些东西迫使响应具有缓存控制:在IIS7中是私有的
- iis7:缓存设置不工作…为什么?
- iis7+asp.net MVC客户端缓存头不工作
- 为ASPX页设置缓存控制
- 缓存控制:没有存储,必须重新验证没有发送到IIS7+ASP.NET MVC中的客户端浏览器
等等
接受的答案是正确的,其中必须设置标题,而不是必须如何设置标题。此方法适用于iis7:
1 2 3 4
| Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.AppendCacheExtension("no-store, must-revalidate");
Response.AppendHeader("Pragma","no-cache");
Response.AppendHeader("Expires","-1"); |
第一行将Cache-control设置为no-cache,第二行添加其他属性no-store, must-revalidate。
- 这对我有用:Response.Cache.SetAllowResponseInBrowserHistory(false); Response.Cache.SetCacheability(HttpCacheability.NoCache); Response.Cache.SetNoStore(); Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);。
除了标题之外,还可以考虑通过https服务您的页面。默认情况下,许多浏览器不会缓存HTTPS。
1 2 3 4 5 6 7 8
| //In .net MVC
[OutputCache(NoStore = true, Duration = 0, VaryByParam ="*")]
public ActionResult FareListInfo(long id)
{
}
// In .net webform
<%@ OutputCache NoStore="true" Duration="0" VaryByParam="*" %> |
完成balusc->answer如果您使用的是Perl,那么可以使用CGI添加HTTP头。
使用Perl:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Use CGI;
sub set_new_query() {
binmode STDOUT,":utf8";
die if defined $query;
$query = CGI->new();
print $query->header(
-expires => 'Sat, 26 Jul 1997 05:00:00 GMT',
-Pragma => 'no-cache',
-Cache_Control => join(', ', qw(
private
no-cache
no-store
must-revalidate
max-age=0
pre-check=0
post-check=0
))
);
} |
使用apache httpd.conf
1 2 3 4 5 6 7 8
| <FilesMatch"\.(html|htm|js|css|pl)$">
FileETag None
<ifModule mod_headers.c>
Header unset ETag
Header set Cache-Control"max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma"no-cache"
Header set Expires"Wed, 11 Jan 1984 05:00:00 GMT"
</ifModule> |
注意:当我尝试使用HTML元时,浏览器忽略了它们并缓存了页面。
我只是想指出,如果有人想要阻止只缓存动态内容,那么添加这些额外的头应该以编程方式进行。
我编辑了项目的配置文件以不附加缓存头,但这也禁用了静态内容的缓存,这通常是不可取的。修改代码中的响应头可以确保将缓存图像和样式文件。
这很明显,但仍值得一提。
还有一个警告。小心使用httpResponse类的clearHeaders方法。如果你鲁莽使用它可能会给你一些瘀伤。就像它给我的。
在actionfilterattribute事件上重定向之后,清除所有头的结果将丢失tempdata存储中的所有会话数据和数据。在执行重定向时,从操作重定向或不清除头更安全。
第二个想法是,我不鼓励所有人使用ClearHeaders方法。最好单独拆下收割台。为了正确设置缓存控制头,我使用以下代码:
1 2
| filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.AppendCacheExtension("no-store, must-revalidate"); |
请参阅以下链接以了解有关缓存的案例研究:
http://securityevaluators.com/knowledge/case-studies/caching/
总结一下,根据文章,只有Cache-Control: no-store在chrome、firefox和ie.ie上工作,但chrome和firefox不接受其他控制。链接是一个很好的阅读,包括缓存和文档概念证明的历史。
我对江户十一〔二〕行没什么好运气。直接添加与HTTP缓存相关的参数(在HTML文档之外)确实对我有用。
下面是使用web.py web.header调用的python中的示例代码。我有目的地修改了与我个人无关的实用程序代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import web
import sys
import PERSONAL-UTILITIES
myname ="main.py"
urls = (
'/', 'main_class'
)
main = web.application(urls, globals())
render = web.template.render("templates/", base="layout", cache=False)
class main_class(object):
def GET(self):
web.header("Cache-control","no-cache, no-store, must-revalidate")
web.header("Pragma","no-cache")
web.header("Expires","0")
return render.main_form()
def POST(self):
msg ="POSTed:"
form = web.input(function = None)
web.header("Cache-control","no-cache, no-store, must-revalidate")
web.header("Pragma","no-cache")
web.header("Expires","0")
return render.index_laid_out(greeting = msg + form.function)
if __name__ =="__main__":
nargs = len(sys.argv)
# Ensure that there are enough arguments after python program name
if nargs != 2:
LOG-AND-DIE("%s: Command line error, nargs=%s, should be 2", myname, nargs)
# Make sure that the TCP port number is numeric
try:
tcp_port = int(sys.argv[1])
except Exception as e:
LOG-AND-DIE ("%s: tcp_port = int(%s) failed (not an integer)", myname, sys.argv[1])
# All is well!
JUST-LOG("%s: Running on port %d", myname, tcp_port)
web.httpserver.runsimple(main.wsgifunc(), ("localhost", tcp_port))
main.run() |