我们的调查表明,并非所有浏览器都以统一的方式尊重 HTTP 缓存指令。
出于安全原因,我们不希望应用程序中的某些页面被Web 浏览器缓存。这必须至少适用于以下浏览器:
- 互联网浏览器 6+
- 火狐 1.5+
- 野生动物园 3+
- 歌剧 9+
- 铬合金
我们的要求来自安全测试。从我们的网站注销后,您可以按返回按钮并查看缓存页面。
我们的调查表明,并非所有浏览器都以统一的方式尊重 HTTP 缓存指令。
出于安全原因,我们不希望应用程序中的某些页面被Web 浏览器缓存。这必须至少适用于以下浏览器:
我们的要求来自安全测试。从我们的网站注销后,您可以按返回按钮并查看缓存页面。
适用于所有提及的客户端(和代理)的正确最小标头集:
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
这Cache-Control
是针对客户端和代理的 HTTP 1.1 规范(并且旁边的某些客户端隐式要求Expires
)。这Pragma
是针对史前客户端的 HTTP 1.0 规范。这Expires
是针对客户端和代理的 HTTP 1.0 和 1.1 规范。在 HTTP 1.1 中,Cache-Control
优先于Expires
,所以它毕竟只适用于 HTTP 1.0 代理。
如果您不关心 IE6 及其在仅使用 HTTPS 提供页面时损坏的缓存no-store
,那么您可以省略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
参数如不相关。此处大多数其他答案中包含的标头仅在您确实要缓存请求时才有意义,因此您根本不需要指定它。max-age
Cache-Control
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.NET Core v3
// using Microsoft.Net.Http.Headers
Response.Headers[HeaderNames.CacheControl] = "no-cache, no-store, must-revalidate";
Response.Headers[HeaderNames.Expires] = "0";
Response.Headers[HeaderNames.Pragma] = "no-cache";
使用 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:
headers["Cache-Control"] = "no-cache, no-store, must-revalidate" # HTTP 1.1.
headers["Pragma"] = "no-cache" # HTTP 1.0.
headers["Expires"] = "0" # Proxies.
使用 Python/Flask:
response = make_response(render_template(...))
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')
)
)
使用围棋:
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.
使用 Clojure(需要 Ring utils):
(require '[ring.util.response :as r])
(-> response
(r/header "Cache-Control" "no-cache, no-store, must-revalidate")
(r/header "Pragma" "no-cache")
(r/header "Expires" 0))
使用 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>
使用 HTML:
<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 元标记。file://
仅当通过URL从本地磁盘文件系统查看页面时,才会使用 HTML 元标记。另见W3 HTML 规范第 5.2.2 章。当您不以编程方式指定它们时请注意这一点,因为网络服务器可以包含一些默认值。
通常,您最好不要指定 HTML 元标记以避免初学者混淆并依赖硬 HTTP 响应标头。此外,特别是那些<meta http-equiv>
标签在 HTML5中是无效的。仅允许HTML5 规范http-equiv
中列出的值。
要验证其中一个,您可以在 Web 浏览器的开发人员工具集的 HTTP 流量监视器中查看/调试它们。您可以在 Chrome/Firefox23+/IE9+ 中按 F12,然后打开“网络”或“网络”选项卡面板,然后单击感兴趣的 HTTP 请求以查看有关 HTTP 请求和响应的所有详细信息。以下屏幕截图来自 Chrome:
首先,这个问答针对的是“网页”(HTML页面),而不是“文件下载”(PDF、zip、Excel等)。您最好将它们缓存起来,并在 URI 路径或查询字符串的某处使用某些文件版本标识符来强制重新下载已更改的文件。无论如何,当在文件下载上应用那些无缓存标头时,当通过 HTTPS 而不是 HTTP 提供文件下载时,请注意 IE7/8 错误。详见IE 无法下载 foo.jsf。IE 无法打开此 Internet 站点。请求的站点不可用或找不到。
(嘿,大家:请不要盲目地复制和粘贴你能找到的所有标题)
首先,后退按钮历史记录不是缓存:
新鲜度模型(第 4.2 节)不一定适用于历史机制。也就是说,历史机制可以显示以前的表示,即使它已经过期。
在旧的 HTTP 规范中,措辞更加强烈,明确告诉浏览器忽略后退按钮历史记录的缓存指令。
Back 应该及时返回(到用户登录的时间)。它不会向前导航到以前打开的 URL。
但是,在实践中,缓存会影响后退按钮,在非常特殊的情况下:
Cache-Control: no-store, must-revalidate
(一些浏览器观察no-store
和一些观察must-revalidate
)你永远不需要任何:
<meta>
带有缓存头——它根本不起作用。完全没用。post-check
/ pre-check
— 这是一个仅限 IE 的指令,仅适用于可缓存资源。如果你愿意,你可以添加:
no-cache
或max-age=0
,这将使资源(URL)“陈旧”,并要求浏览器与服务器检查是否有更新的版本(no-store
已经暗示这更强大)。Expires
HTTP/1.0 客户端的日期是过去的(尽管现在完全不存在真正的仅 HTTP/1.0 客户端)。奖励:新的 HTTP 缓存 RFC。
正如@Kornel 所说,您想要的不是停用缓存,而是停用历史缓冲区。不同的浏览器有自己的微妙方法来禁用历史缓冲区。
在 Chrome (v28.0.1500.95 m) 中,我们只能通过Cache-Control: no-store
.
在 FireFox (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-store
<body onunload="">
在 HTML 中
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-revalidate
Expires: 0
Cache-Control: must-revalidate
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
(仅限 https)
Vary: *
(仅限 https)
结合以上内容为我们提供了适用于 Chrome 28、FireFox 23、IE8、Safari 5.1.7 和 Opera 12.15 的解决方案:( Cache-Control: no-store, must-revalidate
仅限 https)
请注意,需要 https 是因为 Opera 不会停用普通 http 页面的历史缓冲区。如果您真的无法获得 https 并且您准备忽略 Opera,那么您可以做的最好的事情是:
Cache-Control: no-store
<body onunload="">
下面显示了我的测试的原始日志:
HTTP:
Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
<body onunload="">
失败: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=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
<body onunload="">
失败: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=0
Expires: 0
Pragma: no-cache
Vary: *
失败: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=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
失败: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=0
Expires: 0
Pragma: no-cache
Vary: *
<body onunload="">
失败: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=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
<body onunload="">
失败: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=0
Expires: 0
Pragma: no-cache
Vary: *
<body onunload="">
失败: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=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
<body onunload="">
失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15
成功:IE8
Cache-Control: no-store
失败:Safari 5.1.7、Opera 12.15
成功:Chrome 28、FireFox 23、IE8
Cache-Control: no-store
<body onunload="">
失败:Opera 12.15
成功:Chrome 28、FireFox 23、IE8、Safari 5.1.7
Cache-Control: no-cache
失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15
成功:IE8
Vary: *
失败:Chrome 28、FireFox 23、IE8、Safari 5.1.7、Opera 12.15
成功:无
Pragma: no-cache
失败: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=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
<body onunload="">
失败: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=0
Expires: 0
Pragma: no-cache
Vary: *
<body onunload="">
失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15
成功:IE8
Cache-Control: must-revalidate, max-age=0
失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15
成功:IE8
Cache-Control: must-revalidate
Expires: 0
失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15
成功:IE8
Cache-Control: must-revalidate
Expires: Sat, 12 Oct 1991 05:00:00 GMT
失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15
成功:IE8
Cache-Control: private, must-revalidate, proxy-revalidate, s-maxage=0
Pragma: no-cache
Vary: *
<body onunload="">
失败:Chrome 28、FireFox 23、IE8、Safari 5.1.7、Opera 12.15
成功:无
HTTPS:
Cache-Control: private, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
<body onunload="">
失败:Chrome 28、FireFox 23、IE8、Safari 5.1.7、Opera 12.15
成功:无
Cache-Control: private, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
<body onunload="">
失败:Chrome 28、FireFox 23、IE8、Safari 5.1.7、Opera 12.15
成功:无
Vary: *
失败:Chrome 28、Safari 5.1.7、Opera 12.15
成功:FireFox 23、IE8
Pragma: no-cache
失败:Chrome 28、Safari 5.1.7、Opera 12.15
成功:FireFox 23、IE8
Cache-Control: no-cache
失败:Chrome 28、Safari 5.1.7、Opera 12.15
成功:FireFox 23、IE8
Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0
失败:Chrome 28、Safari 5.1.7、Opera 12.15
成功:FireFox 23、IE8
Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
失败:Chrome 28、Safari 5.1.7、Opera 12.15
成功:FireFox 23、IE8
Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
失败:Chrome 28、Safari 5.1.7、Opera 12.15
成功:FireFox 23、IE8
Cache-Control: must-revalidate
失败:Chrome 28、FireFox 23、IE8、Safari 5.1.7
成功:Opera 12.15
Cache-Control: private, must-revalidate, proxy-revalidate, s-maxage=0
<body onunload="">
失败:Chrome 28、FireFox 23、IE8、Safari 5.1.7
成功:Opera 12.15
Cache-Control: must-revalidate, max-age=0
失败:Chrome 28、FireFox 23、Safari 5.1.7
成功:IE8、Opera 12.15
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
<body onunload="">
失败:Chrome 28、Safari 5.1.7
成功:FireFox 23、IE8、Opera 12.15
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
<body onunload="">
失败:Chrome 28、Safari 5.1.7
成功:FireFox 23、IE8、Opera 12.15
Cache-Control: no-store
失败: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=0
Expires: 0
Pragma: no-cache
Vary: *
<body onunload="">
失败: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=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
<body onunload="">
失败:Opera 12.15
成功:Chrome 28、FireFox 23、IE8、Safari 5.1.7
Cache-Control: private, no-cache
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
失败:Chrome 28、Safari 5.1.7、Opera 12.15
成功:FireFox 23、IE8
Cache-Control: must-revalidate
Expires: 0
失败:Chrome 28、FireFox 23、Safari 5.1.7,
成功:IE8、Opera 12.15
Cache-Control: must-revalidate
Expires: Sat, 12 Oct 1991 05:00:00 GMT
失败:Chrome 28、FireFox 23、Safari 5.1.7,
成功:IE8、Opera 12.15
Cache-Control: private, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
<body onunload="">
失败:Chrome 28、FireFox 23、Safari 5.1.7,
成功:IE8、Opera 12.15
Cache-Control: private, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
<body onunload="">
失败:Chrome 28、FireFox 23、Safari 5.1.7,
成功:IE8、Opera 12.15
Cache-Control: private, must-revalidate
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
失败:Chrome 28、Safari 5.1.7
成功:FireFox 23、IE8、Opera 12.15
Cache-Control: no-store, must-revalidate
失败:无
成功:Chrome 28、FireFox 23、IE8、Safari 5.1.7、Opera 12.15
我发现 web.config 路由很有用(试图将其添加到答案中,但似乎没有被接受,所以在这里发布)
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="no-cache, no-store, must-revalidate" />
<!-- HTTP 1.1. -->
<add name="Pragma" value="no-cache" />
<!-- HTTP 1.0. -->
<add name="Expires" value="0" />
<!-- Proxies. -->
</customHeaders>
</httpProtocol>
</system.webServer>
这里是 express / node.js 做同样的方式:
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 使用页面的缓存版本。
经过大量研究和测试,我发现我真正需要的唯一两个标头是:
缓存控制:无存储
变化:*
有关 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 的答案。
经过一番研究,我们得出了以下似乎涵盖大多数浏览器的标头列表:
在 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", "Sat, 26 Jul 1997 05:00:00 GMT"); // HTTP 1.0
在响应中使用 pragma 头是一个妻子的故事。RFC2616 仅将其定义为请求标头
免责声明:我强烈建议阅读@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);
在此处查看更完整的文档。
IE6 有问题
即使您使用“Cache-Control: no-cache”,具有“Content-Encoding: gzip”的内容也会始终被缓存。
http://support.microsoft.com/kb/321722
您可以为 IE6 用户禁用 gzip 压缩(检查“MSIE 6”的用户代理)
对于 ASP.NET Core,创建一个简单的中间件类:
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
app.UseMiddleware<NoCacheMiddleware>();
确保你在之后的某个地方添加这个
app.UseStaticFiles();
这些指令不会减轻任何安全风险。它们实际上是为了迫使 UA 刷新易失性信息,而不是阻止 UA 保留信息。看到这个类似的问题。至少,不能保证任何路由器、代理等也不会忽略缓存指令。
更积极的一点是,有关计算机物理访问、软件安装等的政策将使您在安全性方面领先于大多数公司。如果这些信息的消费者是公众,你唯一能做的就是帮助他们了解,一旦信息到达他们的机器,那台机器就是他们的责任,而不是你的。
将修改后的 http 标头设置为 1995 年的某个日期通常可以解决问题。
这是一个例子:
过期:1995 年 11 月 15 日星期三 04:58:08 GMT 最后修改时间:周三,1995 年 11 月 15 日 04:58:08 GMT 缓存控制:无缓存,必须重新验证
HTTP 1.1的 RFC说正确的方法是为以下内容添加 HTTP 标头:
缓存控制:无缓存
如果旧浏览器不正确地兼容 HTTP 1.1,它们可能会忽略这一点。对于那些你可以尝试标题的人:
Pragma:无缓存
这也应该适用于 HTTP 1.1 浏览器。
header 函数的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);
如果您在使用 IE6-IE8 over SSL 和 cache:no-cache 标头(和类似值)时遇到 MS Office 文件的下载问题,您可以使用 cache:private,no-store 标头并在 POST 请求时返回文件。有用。
在我的情况下,我用这个解决了 chrome 中的问题
<form id="form1" runat="server" autocomplete="off">
出于安全原因,当用户单击返回按钮时,我需要清除以前表单数据的内容
接受的答案似乎不适用于 IIS7+,因为关于 II7 中未发送缓存标头的大量问题:
等等
接受的答案是正确的,其中必须设置标头,但不是必须如何设置标头。这种方式适用于 IIS7:
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
通过设置 Pragma: no-cache,我在所有浏览器中获得了最好和最一致的结果
BalusC 提供的答案中的标题不会阻止 Safari 5(可能还有旧版本)在使用浏览器的后退按钮时显示浏览器缓存中的内容。防止这种情况的一种方法是向 body 标记添加一个空的 onunload 事件处理程序属性:
<body onunload="">
这个 hack 显然破坏了 Safari 中的后向缓存:单击后退按钮时是否存在跨浏览器 onload 事件?
另外,为了更好地衡量,如果您使用它来启用缓存,请确保您ExpiresDefault
在文件中重置。.htaccess
ExpiresDefault "access plus 0 seconds"
之后,您可以使用ExpiresByType
为要缓存的文件设置特定值:
ExpiresByType image/x-icon "access plus 3 month"
如果您的动态文件(例如 php 等)正在被浏览器缓存,而您无法弄清楚原因,这也可能会派上用场。检查ExpiresDefault
。
除了标题之外,还可以考虑通过https为您的页面提供服务。许多浏览器默认不会缓存 https。
//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:
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
<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 META 时,浏览器会忽略它们并缓存页面。
我只想指出,如果有人想阻止仅缓存动态内容,则应以编程方式添加这些额外的标头。
我编辑了项目的配置文件以附加无缓存标头,但这也禁用了缓存静态内容,这通常是不可取的。修改代码中的响应标头可确保缓存图像和样式文件。
这很明显,但仍然值得一提。
另一个警告。小心使用 HttpResponse 类中的 ClearHeaders 方法。如果你鲁莽使用它可能会给你一些瘀伤。就像它给了我一样。
在 ActionFilterAttribute 事件上重定向后,清除所有标头的后果是丢失所有会话数据和 TempData 存储中的数据。从 Action 重定向或在重定向发生时不清除标头会更安全。
再三考虑,我不鼓励所有人使用 ClearHeaders 方法。最好单独删除标题。为了正确设置 Cache-Control 标头,我正在使用以下代码:
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 不接受。该链接是一个很好的阅读完整的缓存和记录概念证明的历史。
我对<head><meta>
元素没有运气。直接添加 HTTP 缓存相关参数(在 HTML 文档之外)确实对我有用。
下面是使用 web.pyweb.header
调用的 Python 示例代码。我故意编辑了我个人无关的实用程序代码。
导入网页 导入系统 导入个人工具 我的名字=“main.py” 网址 = ( '/', 'main_class' ) main = web.application(urls, globals()) render = web.template.render("templates/", base="layout", cache=False) 类主类(对象): 定义获取(自我): web.header("缓存控制","无缓存、无存储、必须重新验证") web.header("Pragma", "no-cache") web.header("过期", "0") 返回 render.main_form() def POST(自我): msg = "已发布:" 表单 = web.input(函数 = 无) web.header("缓存控制","无缓存、无存储、必须重新验证") web.header("Pragma", "no-cache") web.header("过期", "0") return render.index_laid_out(问候 = msg + form.function) 如果 __name__ == "__main__": nargs = len(sys.argv) # 确保python程序名后面有足够的参数 如果纳尔格斯!= 2: LOG-AND-DIE("%s: 命令行错误, nargs=%s, 应该是 2", myname, nargs) # 确保 TCP 端口号是数字 尝试: tcp_port = int(sys.argv[1]) 例外为 e: LOG-AND-DIE ("%s: tcp_port = int(%s) failed (not an integer)", myname, sys.argv[1]) # 一切都很好! JUST-LOG("%s: 在端口 %d 上运行", myname, tcp_port) web.httpserver.runsimple(main.wsgifunc(), ("localhost", tcp_port)) 主运行()
我已经以这种方式解决了。
2个考虑:
1)服务器端事件不会在点击后触发,而不是javascript。
2) 我有 2 个 javascript 来读/写 cookie
function setCookie(name, value, days)
{
var expires = "";
if (days)
{
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
function getCookie(name)
{
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (var i = ca.length - 1; i >= 0; i--)
{
var c = ca[i];
while (c.charAt(0) == ' ')
{
c = c.substring(1, c.length);
}
if (c.indexOf(nameEQ) == 0)
{
return c.substring(nameEQ.length, c.length);
}
}
return null;
}
在我的 Page_Load 我插入了这个:(这不是在点击后触发的)
protected void Page_Load(object sender, EventArgs e)
{
Page.RegisterClientScriptBlock("", "<script>setCookie('" + Session.SessionID + "', '" + Login + "', '100');</script>");
}
其中“登录”是我的 id 值,注销后为 -1(您可以使用其他东西,例如布尔值)。
然后在我的页面中我添加了这个:(这是在点击后触发的)
<script type="text/javascript">
if (getCookie('<%= Session.SessionID %>') < 0)
{
if (history.length > 0)
{
history.go(+1);
}
}
</script>
没有其他的。
使用此解决方案,在每个页面上都启用后单击,并且仅在同一浏览器上的每个页面上注销后才禁用。
您可以使用位置块来设置单个文件而不是整个应用程序在 IIS 中获取缓存
<location path="index.html">
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="no-cache" />
</customHeaders>
</httpProtocol>
</system.webServer>
</location>
不确定我的回答是否听起来简单而愚蠢,也许您很久以前就已经知道了,但是由于防止某人使用浏览器后退按钮查看您的历史页面是您的目标之一,您可以使用:
window.location.replace("https://www.example.com/page-not-to-be-viewed-in-browser-history-back-button.html");
当然,这可能无法在整个站点上实现,但至少对于一些关键页面,您可以这样做。希望这可以帮助。