如何在所有浏览器中控制网页缓存?
我们的调查表明,并非所有浏览器都以统一的方式遵守http缓存指令。
出于安全原因,我们不希望Web浏览器永远缓存应用程序中的某些页面。这必须至少适用于以下浏览器:
- Internet Explorer 6+
- Firefox 1.5以上
- Safari 3+
- 歌剧9+
- 铬合金
我们的要求来自安全测试。从我们的网站注销后,我们可以按返回按钮并查看缓存的页面。
解决方案
回答
通常在1995年将修改后的http标头设置为某个日期即可。
这是一个例子:
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
回答
经过一些研究,我们提出了以下标头列表,这些标头似乎涵盖了大多数浏览器:
- 过期:格林尼治标准时间1997年7月26日星期一
- 缓存控制:无缓存,私有,必须重新验证,max-stale = 0,post-check = 0,pre-check = 0无存储
- 语法:无快取
在ASP.NET中,我们使用以下代码段添加了这些代码:
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
回答
RFC for HTTP 1.1表示正确的方法是为以下项添加HTTP标头:
缓存控制:无缓存
如果较旧的浏览器未正确符合HTTP 1.1,则可能会忽略此设置。对于那些,我们可以尝试标题:
语法:无缓存
这也应该适用于HTTP 1.1浏览器。
回答
标头函数的PHP文档有一个相当完整的示例(由第三方提供):
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);
回答
通过设置,我在所有浏览器中都获得了最好,最一致的结果
语法:无缓存
回答
响应中使用pragma标头是一个妻子的故事。 RFC2616仅将其定义为请求标头
http://www.mnot.net/cache_docs/#PRAGMA
回答
免责声明:我强烈建议阅读@BalusC的答案。在阅读以下缓存教程之后:http://www.mnot.net/cache_docs/(我也建议我们阅读它),我相信它是正确的。但是,出于历史原因(并且因为我已经对它进行了测试),我将在下面提供我的原始答案:
我尝试了PHP的"已接受"答案,但该方法对我不起作用。然后,我做了一些研究,发现了一个细微的变体,对其进行了测试,然后它起作用了。这里是:
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()"函数调用中,则他必须执行以下操作:
header('Cache-Control: this'); header('Cache-Control: and, this', false);
在这里查看更多完整的文档。
回答
这些指令不会减轻任何安全风险。它们的真正目的是迫使UA刷新易失性信息,而不是阻止UA保留信息。看到这个类似的问题。至少,不能保证任何路由器,代理等也不会忽略缓存指令。
更为积极的一点是,有关物理访问计算机,软件安装等方面的策略将使我们在安全性方面领先于大多数公司。如果这些信息的使用者是公众的成员,那么我们唯一能做的就是帮助他们了解,一旦信息进入他们的机器,那台机器就是他们的责任,而不是责任。
回答
除了标题之外,还可以考虑通过https服务页面。默认情况下,许多浏览器不会缓存https。
回答
我发现此页面上的所有答案仍然存在问题。特别是,我注意到当我们通过单击"后退"按钮访问IE8时,它们都无法阻止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和Opera 9-10上,单击"后退"按钮仍会导致加载缓存的版本。在我测试过的所有其他浏览器上,它们都确实从服务器获取了一个新版本。到目前为止,我还没有找到任何可以使这些浏览器在我们按下"后退"按钮时不返回页面的缓存版本的标头集。
更新:写完这个答案后,我意识到我们的Web服务器正在将自己标识为HTTP 1.0服务器。我列出的标头是正确的标头,以便浏览器不会缓存来自HTTP 1.0服务器的响应。对于HTTP 1.1服务器,请查看BalusC的答案。
回答
适用于所有提到的客户端(和代理)的正确的最小标头集:
Cache-Control: no-cache, no-store, must-revalidate Pragma: no-cache Expires: 0
Cache-Control是针对客户端和代理的HTTP 1.1规范(并且某些客户端在Expires旁边隐式要求)。 " Pragma"是针对史前客户端的HTTP 1.0规范。 "过期"是针对客户端和代理的HTTP 1.0和1.1规范。在HTTP 1.1中,Cache-Control
优先于Expires
,因此仅适用于HTTP 1.0代理。
如果仅通过" no-store"通过HTTPS服务页面时,如果我们不关心IE6及其中断的缓存,则可以省略" Cache-Control:no-cache"。
Cache-Control: no-store, must-revalidate Pragma: no-cache Expires: 0
如果我们不关心IE6或者HTTP 1.0客户端(HTTP 1.1于1997年推出),则可以省略" Pragma"。
Cache-Control: no-store, must-revalidate Expires: 0
如果我们也不关心HTTP 1.0代理,则可以省略Expires。
Cache-Control: no-store, must-revalidate
另一方面,如果服务器自动包含有效的" Date"标头,则理论上我们也可以省略" Cache-Control",而仅依靠" Expires"。
Date: Wed, 24 Aug 2016 18:32:02 GMT Expires: 0
但这可能会失败,例如最终用户操纵操作系统日期,而客户端软件则依赖它。
如果指定了上述" Cache-Control"参数,则其他" Cache-Control"参数(例如" max-age")均无关紧要。大多数其他答案中包含的" Last-Modified"标头仅在我们确实要缓存请求时才很有趣,因此根本不需要指定它。
使用PHP:
header("Cache-Control: no-cache, no-store, must-revalidate"); // HTTP 1.1. header("Pragma: no-cache"); // HTTP 1.0. header("Expires: 0"); // Proxies.
使用Java Servlet或者Node.js:
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
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:
// `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:
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:
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:
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate" # HTTP 1.1. response.headers["Pragma"] = "no-cache" # HTTP 1.0. response.headers["Expires"] = "0" # Proxies.
使用Python / Django:
response["Cache-Control"] = "no-cache, no-store, must-revalidate" # HTTP 1.1. response["Pragma"] = "no-cache" # HTTP 1.0. response["Expires"] = "0" # Proxies.
使用Python /金字塔:
request.response.headerlist.extend( ( ('Cache-Control', 'no-cache, no-store, must-revalidate'), ('Pragma', 'no-cache'), ('Expires', '0') ) )
使用Google Go:
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
文件:
<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:
<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" />
要知道的重要一点是,当通过HTTP连接为HTML页面提供服务,并且HTTP响应标头和HTML<meta http-equiv>
标签中都存在标头时,则HTTP响应标头中指定的标头将优先于HTML meta标签。仅当通过file://
URL从本地磁盘文件系统查看页面时,才使用HTML元标记。另请参阅W3 HTML规范第5.2.2章。当我们不以编程方式指定它们时,请务必小心,因为Web服务器可以包含一些默认值。
通常,最好不要指定HTML元标记,以免引起初学者的困惑,而要依赖硬HTTP响应标头。而且,特别是那些<meta http-equiv>标签在HTML5中是无效的。仅允许HTML5规范中列出的" http-equiv"值。
要验证彼此,可以在webbrowser开发人员工具集的HTTP流量监视器中查看/调试它们。我们可以通过在Chrome / Firefox23 + / IE9 +中按F12,然后打开"网络"或者"网络"标签面板,然后单击感兴趣的HTTP请求以发现有关HTTP请求和响应的所有详细信息,来到达那里。以下屏幕截图来自Chrome:
首先,此问题和答案针对"网页"(HTML页面),而不是"文件下载"(PDF,zip,Excel等)。我们最好将它们缓存起来,并在URI路径或者querystring中的某处使用一些文件版本标识符,以强制在更改的文件上重新下载。无论如何,当在文件下载上应用这些无缓存头时,请注意通过HTTPS而不是HTTP提供文件下载时的IE7 / 8错误。有关详细信息,请参见IE无法下载foo.jsf。 IE无法打开此网站。请求的站点不可用或者找不到。