我们的调查表明,并非所有浏览器都以统一的方式遵守HTTP缓存指令。
出于安全原因,我们不希望Web浏览器缓存应用程序中的某些页面。这至少适用于以下浏览器:
- Internet Explorer 6+
- 火狐1.5 +
- 狩猎3号
- 歌剧9 +
- 铬
我们的要求来自安全测试。从我们的网站注销后,您可以按后退按钮并查看缓存页面。
介绍
在所有提到的客户机(和代理)上工作的正确的最小头集:
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站点。请求的站点不可用或找不到。
(嘿,各位:请不要盲目复制和粘贴所有可以找到的邮件头)
首先,后退按钮历史记录不是缓存:
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。
正如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好的。
好啊。
我发现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();
}); |
我发现这一页上的所有答案都有问题。特别是,我注意到,当您通过点击后退按钮访问该页面时,它们中没有一个会阻止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的答案。
经过一番研究,我们得出了以下似乎涵盖大多数浏览器的标题列表:
- 有效期至: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
在响应中使用pragma头是一个妻子的故事。RFC2616仅将其定义为请求头
http://www.mnot.net/cache_docs/pragma
免责声明:我强烈建议阅读@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); |
请参阅此处的更多完整文档。
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>(); |
一定要在后面加上这个
HTTP 1.1的RFC表示,正确的方法是为以下对象添加一个HTTP头:
缓存控制:无缓存
如果旧的浏览器不符合HTTP1.1,它们可能会忽略这一点。对于那些你可以尝试的标题:
pragma:没有缓存
这也应该适用于HTTP 1.1浏览器。
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); |
这些指令不能减轻任何安全风险。它们实际上是为了迫使行动单位更新易变信息,而不是阻止行动单位保留信息。看看这个类似的问题。至少,不能保证任何路由器、代理等也不会忽略缓存指令。
更积极的是,有关计算机物理访问、软件安装等方面的政策将使您在安全性方面远远领先于大多数公司。如果这些信息的消费者是公众,你唯一能做的就是帮助他们理解,一旦这些信息击中他们的机器,那机器就是他们的责任,而不是你的责任。
将修改后的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 |
如果您在SSL和缓存上遇到IE6-IE8下载问题:MS Office文件没有缓存头(和类似的值),则可以使用缓存:private,no store header,以及post请求时返回的文件。它起作用了。
在我的例子中,我用这个解决了Chrome的问题
1
| <form id="form1" runat="server" autocomplete="off"> |
当用户出于安全原因单击后退按钮时,我需要清除previus表单数据的内容
另外,为了更好地衡量,如果您使用.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事件?
通过设置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。
除了标题之外,还可以考虑通过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() |