我们的调查表明,并非所有浏览器都以统一的方式尊重HTTP缓存指令。

出于安全原因,我们不希望应用程序中的某些页面被web浏览器缓存。这必须至少适用于以下浏览器:

Internet Explorer 6+Firefox 1.5+Safari 3+歌剧9+铬

我们的要求来自安全测试。从我们的网站注销后,您可以按后退按钮并查看缓存的页面。


将修改后的http头设置为1995年的某个日期通常会起作用。

下面是一个示例:

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日星期六05:00:00 GMT缓存控制:无缓存,私有,必须重新验证,最大失效=0,后检查=0,预检查=0无存储Pragma:无缓存

在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 

从以下位置找到:http://forums.asp.net/t/1013531.aspx

RFC for HTTP 1.1指出,正确的方法是为以下内容添加HTTP标头:

缓存控制:无缓存

如果较旧的浏览器不符合HTTP 1.1,它们可能会忽略这一点。对于那些你可以尝试标题:

Pragma:无缓存

这也适用于HTTP1.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:无缓存

在响应中使用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()调用。因此,在设置缓存控件时,例如,如果不想将所有参数放在一个header()函数调用中,则必须执行以下操作:

header('Cache-Control: this');
header('Cache-Control: and, this', false);

请在此处查看更完整的文档。

这些指令不会减轻任何安全风险。它们实际上是为了迫使UA更新不稳定的信息,而不是阻止UA保留信息。看到这个类似的问题。至少,不能保证任何路由器、代理等也不会忽略缓存指令。

更积极的是,有关计算机物理访问、软件安装等方面的政策将使您在安全方面领先于大多数公司。如果这些信息的消费者是公众,你唯一能做的就是帮助他们明白,一旦信息到达他们的机器,那台机器就是他们的责任,而不是你的责任。

除了标题之外,还可以考虑通过https为页面提供服务。许多浏览器默认不会缓存https。

我发现这一页上的所有答案仍然存在问题。特别是,我注意到,当您通过单击后退按钮访问页面时,它们都不会阻止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的答案。

介绍

适用于所有提到的客户端(和代理)的正确的最小标头集:

Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0

缓存控制符合客户端和代理的HTTP 1.1规范(某些客户端在Expires旁边隐式要求)。Pragma符合史前客户端的HTTP 1.0规范。对于客户端和代理,Expires符合HTTP 1.0和1.1规范。在HTTP 1.1中,缓存控制优先于过期,因此它毕竟只适用于HTTP 1.0代理。

如果您不关心IE6及其在HTTPS上仅提供无存储的页面时损坏的缓存,那么您可以忽略缓存控制:无缓存。

Cache-Control: no-store, must-revalidate
Pragma: no-cache
Expires: 0

如果您不关心IE6或HTTP 1.0客户端(1997年引入了HTTP 1.1),那么可以省略Pragma。

Cache-Control: no-store, must-revalidate
Expires: 0

如果您也不关心HTTP1.0代理,那么可以忽略Expires。

Cache-Control: no-store, must-revalidate

另一方面,如果服务器自动包含有效的Date标头,那么理论上也可以省略CacheControl,只依赖Expires。

Date: Wed, 24 Aug 2016 18:32:02 GMT
Expires: 0

但是,如果最终用户操纵操作系统日期,而客户端软件依赖该日期,则这可能会失败。

如果指定了上述缓存控制参数,则其他缓存控制参数(如最大年龄)无关紧要。这里大多数其他答案中包含的LastModified标头只有在您确实想要缓存请求时才有意思,因此根本不需要指定它。

如何设置?

使用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.

使用RubyonRails:

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/Pyramid:

request.response.headerlist.extend(
    (
        ('Cache-Control', 'no-cache, no-store, must-revalidate'),
        ('Pragma', 'no-cache'),
        ('Expires', '0')
    )
)

使用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.

使用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">

HTML元标记与HTTP响应标头

需要知道的是,当HTML页面通过HTTP连接提供服务,并且HTTP响应标头和HTML<meta-HTTP-equiv>标记中都存在标头时,HTTP响应标头中指定的标头将优先于HTML元标记。HTML元标记仅在通过file://URL从本地磁盘文件系统查看页面时使用。另请参见W3 HTML规范第5.2.2章。当您不以编程方式指定它们时,请注意这一点,因为Web服务器可以包括一些默认值。

通常,最好不要指定HTML元标记,以避免初学者混淆,并依赖硬HTTP响应头。此外,特别是那些<meta-http-equiv>标签在HTML5中是无效的。仅允许HTML5规范中列出的http equiv值。

验证实际HTTP响应标头

要验证两者,您可以在web浏览器开发人员工具集的HTTP流量监视器中查看/调试它们。您可以通过在Chrome/Firefox23+/IE9+中按F12,然后打开“网络”或“网络”选项卡面板,然后单击感兴趣的HTTP请求以了解有关HTTP请求和响应的所有详细信息。以下截图来自Chrome:

我也想在文件下载时设置这些标题

首先,这个问题和答案针对的是“网页”(HTML页面),而不是“文件下载”(PDF、zip、Excel等)。您最好将它们缓存起来,并使用URI路径或查询字符串中的某个文件版本标识符强制重新下载已更改的文件。无论如何,当在文件下载上应用这些无缓存头时,当通过HTTPS而不是HTTP提供文件下载时,请注意IE7/8错误。有关详细信息,请参阅IE无法下载foo.jsf。IE无法打开此网站。请求的站点不可用或找不到。

(嘿,大家:请不要盲目地复制和粘贴所有你能找到的标题)

首先,后退按钮历史记录不是缓存:

新鲜度模型(第4.2节)不一定适用于历史机制。也就是说,历史机制可以显示以前的表示,即使它已经过期。

在旧的HTTP规范中,措辞更加强硬,明确告诉浏览器忽略后退按钮历史的缓存指令。

Back应该返回到时间(用户登录时的时间)。它不会导航到以前打开的URL。

然而,实际上,在非常特殊的情况下,缓存会影响后退按钮:

页面必须通过HTTPS传递,否则,这种缓存破坏将不可靠。此外,如果您没有使用HTTPS,那么您的页面很容易以其他方式被窃取登录信息。您必须发送缓存控制:无存储,必须重新验证(某些浏览器观察到无存储,有些浏览器观察到必须重新验证)

您永远不需要:

<meta>带有缓存头-它根本不起作用。完全没用。后检查/预检查-这是一个仅适用于可计算资源的IE指令。发送相同的标题两次或十几次。一些PHP片段实际上取代了以前的头,导致只发送最后一个。

如果需要,可以添加:

没有缓存或最大年龄=0,这将使资源(URL)“过时”,并要求浏览器与服务器检查是否有更新的版本(没有商店已经暗示了这一点)。对于HTTP/1.0客户端,过期日期为过去的日期(尽管现在真正的HTTP/1.0客户机完全不存在)。


好处:新的HTTP缓存RFC。

当使用浏览器的后退按钮时,BalusC提供的答案中的标题不会阻止Safari 5(以及可能更旧的版本)显示浏览器缓存中的内容。防止这种情况的一种方法是在body标记中添加一个空onunload事件处理程序属性:

<body onunload=""> 

这个黑客显然破坏了Safari中的前向缓存:当单击后退按钮时,是否存在跨浏览器加载事件?

我发现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();
});

如果您面临通过SSL和cache:MS Office文件的IE6-IE8下载问题,则可以在POST请求时使用cache:private、no store header和return file。它起作用了。

//In .net MVC
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public ActionResult FareListInfo(long id)
{
}

// In .net webform
<%@ OutputCache NoStore="true" Duration="0" VaryByParam="*" %>

IE6中存在错误

即使使用“缓存控制:无缓存”,也始终缓存具有“内容编码:gzip”的内容。

http://support.microsoft.com/kb/321722

您可以为IE6用户禁用gzip压缩(检查用户代理中的“MSIE6”)

在我的情况下,我用这个解决了chrome中的问题

<form id="form1" runat="server" autocomplete="off">

当用户出于安全原因单击“返回”按钮时,我需要清除先前表单数据的内容

正如@Kornel所说,您想要的不是停用缓存,而是停用历史缓冲区。不同的浏览器有自己微妙的方法来禁用历史缓冲区。

在Chrome(v28.0.1500.95 m)中,我们只能通过缓存控制来做到这一点:无存储。

在FireFox(23.0.1版)中,以下任何一项都可以工作:

缓存控制:无存储缓存控制:无缓存(仅限https)Pragma:无缓存(仅限https)变量:*(仅限https)

在Opera(v12.15)中,我们只能通过缓存控制:必须重新验证(仅限https)。

在Safari(v5.1.7、7534.57.2)中,以下任何一项都可以:

缓存控制:无存储<body onunload=“”>html格式缓存控制:无存储(仅限https)

在IE8(v8.0.6001.18702IC)中,以下任何一项都有效:

缓存控制:必须重新验证,最大年龄=0缓存控制:无缓存缓存控制:无存储缓存控制:必须重新验证过期时间:0缓存控制:必须重新验证有效期:1991年10月12日星期六05:00:00 GMTPragma:无缓存(仅限https)变量:*(仅限https)

结合以上内容,我们得到了适用于Chrome 28、FireFox 23、IE8、Safari 5.1.7和Opera 12.15的解决方案:缓存控制:无存储,必须重新验证(仅限https)

请注意,需要https,因为Opera不会停用普通http页面的历史缓冲区。如果你真的无法获得https,并且你准备忽略Opera,那么最好的办法就是:

Cache-Control: no-store
<body onunload="">

下面显示了我的测试原始日志:

HTTP:

缓存控制:私有,无缓存,无存储,必须重新验证,最大年龄=0,代理重新验证,s-maxage=0过期时间:0Pragma:无缓存变化:*<body onunload=“”>失败:Opera 12.15成功:Chrome 28、FireFox 23、IE8、Safari 5.1.7缓存控制:私有,无缓存,无存储,必须重新验证,最大年龄=0,代理重新验证,s-maxage=0有效期:1991年10月12日星期六05:00:00 GMTPragma:无缓存变化:*<body onunload=“”>失败:Opera 12.15成功:Chrome 28、FireFox 23、IE8、Safari 5.1.7缓存控制:私有,无缓存,无存储,必须重新验证,最大年龄=0,代理重新验证,s-maxage=0过期时间:0Pragma:无缓存变化:*失败:Safari 5.1.7,Opera 12.15成功:Chrome 28、FireFox 23、IE8缓存控制:私有,无缓存,无存储,必须重新验证,最大年龄=0,代理重新验证,s-maxage=0有效期:1991年10月12日星期六05:00:00 GMTPragma:无缓存变化:*失败:Safari 5.1.7,Opera 12.15成功:Chrome 28、FireFox 23、IE8缓存控制:私有,无缓存,必须重新验证,最大年龄=0,代理重新验证,s-maxage=0过期时间:0Pragma:无缓存变化:*<body onunload=“”>失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15成功:IE8缓存控制:私有,无缓存,必须重新验证,最大年龄=0,代理重新验证,s-maxage=0有效期:1991年10月12日星期六05:00:00 GMTPragma:无缓存变化:*<body onunload=“”>失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15成功:IE8缓存控制:私有,无缓存,必须重新验证,最大年龄=0,代理重新验证,s-maxage=0过期时间:0Pragma:无缓存变化:*<body onunload=“”>失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15成功:IE8缓存控制:私有,无缓存,必须重新验证,最大年龄=0,代理重新验证,s-maxage=0有效期:1991年10月12日星期六05:00:00 GMTPragma:无缓存变化:*<body onunload=“”>失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15成功:IE8缓存控制:无存储失败:Safari 5.1.7,Opera 12.15成功:Chrome 28、FireFox 23、IE8缓存控制:无存储<body onunload=“”>失败:Opera 12.15成功:Chrome 28、FireFox 23、IE8、Safari 5.1.7缓存控制:无缓存失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15成功:IE8变化:*失败:Chrome 28、FireFox 23、IE8、Safari 5.1.7、Opera 12.15成功:无Pragma:无缓存失败:Chrome 28、FireFox 23、IE8、Safari 5.1.7、Opera 12.15成功:无缓存控制:私有,无缓存,必须重新验证,最大年龄=0,代理重新验证,s-maxage=0有效期:1991年10月12日星期六05:00:00 GMTPragma:无缓存变化:*<body onunload=“”>失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15成功:IE8缓存控制:私有,无缓存,必须重新验证,最大年龄=0,代理重新验证,s-maxage=0过期时间:0Pragma:无缓存变化:*<body onunload=“”>失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15成功:IE8缓存控制:必须重新验证,最大年龄=0失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15成功:IE8缓存控制:必须重新验证过期时间:0失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15成功:IE8缓存控制:必须重新验证有效期:1991年10月12日星期六05:00:00 GMT失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15成功:IE8缓存控制:私有,必须重新验证,代理重新验证,s-maxage=0Pragma:无缓存变化:*<body onunload=“”>失败:Chrome 28、FireFox 23、IE8、Safari 5.1.7、Opera 12.15成功:无

HTTPS:

缓存控制:私有,最大年龄=0,代理重新验证,s-maxage=0过期时间:0<body onunload=“”>失败:Chrome 28、FireFox 23、IE8、Safari 5.1.7、Opera 12.15成功:无缓存控制:私有,最大年龄=0,代理重新验证,s-maxage=0有效期:1991年10月12日星期六05:00:00 GMT<body onunload=“”>失败:Chrome 28、FireFox 23、IE8、Safari 5.1.7、Opera 12.15成功:无变化:*失败:Chrome 28、Safari 5.1.7、Opera 12.15成功:FireFox 23,IE8Pragma:无缓存失败:Chrome 28、Safari 5.1.7、Opera 12.15成功:FireFox 23,IE8缓存控制:无缓存失败:Chrome 28、Safari 5.1.7、Opera 12.15成功:FireFox 23,IE8缓存控制:私有,无缓存,最大年龄=0,代理重新验证,s-maxage=0失败:Chrome 28、Safari 5.1.7、Opera 12.15成功:FireFox 23,IE8缓存控制:私有,无缓存,最大年龄=0,代理重新验证,s-maxage=0过期时间:0Pragma:无缓存变化:*失败:Chrome 28、Safari 5.1.7、Opera 12.15成功:FireFox 23,IE8缓存控制:私有,无缓存,最大年龄=0,代理重新验证,s-maxage=0有效期:1991年10月12日星期六05:00:00 GMTPragma:无缓存变化:*失败:Chrome 28、Safari 5.1.7、Opera 12.15成功:FireFox 23,IE8缓存控制:必须重新验证失败:Chrome 28、FireFox 23、IE8、Safari 5.1.7成功:Opera 12.15缓存控制:私有,必须重新验证,代理重新验证,s-maxage=0<body onunload=“”>失败:Chrome 28、FireFox 23、IE8、Safari 5.1.7成功:Opera 12.15缓存控制:必须重新验证,最大年龄=0失败:Chrome 28、FireFox 23、Safari 5.1.7成功:IE8,Opera 12.15缓存控制:私有,无缓存,必须重新验证,最大年龄=0,代理重新验证,s-maxage=0有效期:1991年10月12日星期六05:00:00 GMTPragma:无缓存变化:*<body onunload=“”>失败:Chrome 28,Safari 5.1.7成功:FireFox 23、IE8、Opera 12.15缓存控制:私有,无缓存,必须重新验证,最大年龄=0,代理重新验证,s-maxage=0过期时间:0Pragma:无缓存变化:*<body onunload=“”>失败:Chrome 28,Safari 5.1.7成功:FireFox 23、IE8、Opera 12.15缓存控制:无存储失败:Opera 12.15成功:Chrome 28、FireFox 23、IE8、Safari 5.1.7缓存控制:私有,无缓存,无存储,最大年龄=0,代理重新验证,s-maxage=0过期时间:0Pragma:无缓存变化:*<body onunload=“”>失败:Opera 12.15成功:Chrome 28、FireFox 23、IE8、Safari 5.1.7缓存控制:私有,无缓存,无存储,最大年龄=0,代理重新验证,s-maxage=0有效期:1991年10月12日星期六05:00:00 GMTPragma:无缓存变化:*<body onunload=“”>失败:Opera 12.15成功:Chrome 28、FireFox 23、IE8、Safari 5.1.7缓存控制:私有,无缓存有效期:1991年10月12日星期六05:00:00 GMTPragma:无缓存变化:*失败:Chrome 28、Safari 5.1.7、Opera 12.15成功:FireFox 23,IE8缓存控制:必须重新验证过期时间:0失败:Chrome 28、FireFox 23、Safari 5.1.7、,成功:IE8,Opera 12.15缓存控制:必须重新验证有效期:1991年10月12日星期六05:00:00 GMT失败:Chrome 28、FireFox 23、Safari 5.1.7、,成功:IE8,Opera 12.15缓存控制:私有,必须重新验证,最大年龄=0,代理重新验证,s-maxage=0过期时间:0<body onunload=“”>失败:Chrome 28、FireFox 23、Safari 5.1.7、,成功:IE8,Opera 12.15缓存控制:私有,必须重新验证,最大年龄=0,代理重新验证,s-maxage=0有效期:1991年10月12日星期六05:00:00 GMT<body onunload=“”>失败:Chrome 28、FireFox 23、Safari 5.1.7、,成功:IE8,Opera 12.15缓存控制:私有,必须重新验证有效期:1991年10月12日星期六05:00:00 GMTPragma:无缓存变化:*失败:Chrome 28,Safari 5.1.7成功:FireFox 23、IE8、Opera 12.15缓存控制:没有存储,必须重新验证失败:无成功:Chrome 28、FireFox 23、IE8、Safari 5.1.7、Opera 12.15

完成BalusC->答案如果您使用的是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 
                                           ))
        );
    }

使用apachehttpd.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时,浏览器忽略了它们并缓存了页面。

接受的答案似乎不适用于IIS7+,因为II7中存在大量关于未发送缓存头的问题:

某些事情正在迫使响应具有缓存控制:IIS7中的私有IIS7:缓存设置不工作。。。为什么?IIS7+ASP.NET MVC客户端缓存标头不工作为aspx页面设置缓存控制缓存控制:没有存储,必须重新验证,不能发送到IIS7+ASP.NET MVC中的客户端浏览器

等等

接受的答案是正确的,必须在哪些标题中设置,但不能在如何设置标题中设置。这种方式适用于IIS7:

Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.AppendCacheExtension("no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "-1");

第一行将Cache控件设置为no Cache,第二行添加其他属性no store,must revalidate

我只想指出,如果有人想阻止只缓存动态内容,那么应该以编程方式添加这些额外的头。

我编辑了项目的配置文件,不附加缓存头,但这也禁用了缓存静态内容,这通常是不可取的。修改代码中的响应头可以确保缓存图像和样式文件。

这很明显,但仍值得一提。

还有一个警告。请小心使用HttpResponse类中的ClearHeaders方法。如果你鲁莽地使用它,它可能会给你一些瘀伤。就像它给我的。

重定向ActionFilterAttribute事件后,清除所有标头的后果是丢失所有会话数据和TempData存储中的数据。从Action重定向或在重定向时不清除标头更安全。

再次考虑后,我不鼓励所有人使用ClearHeaders方法。最好单独删除标题。为了正确设置缓存控制头,我使用了以下代码:

filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.AppendCacheExtension("no-store, must-revalidate");

请参阅此链接以获取有关缓存的案例研究:

http://securityevaluators.com/knowledge/case_studies/caching/

总之,根据文章,只有缓存控制:没有商店在Chrome、Firefox和IE上运行。IE接受其他控制,但Chrome和Firefox不接受。该链接是一个很好的阅读,包括缓存和记录概念证明的历史。

对于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();

我在<head><meta>元素方面运气不佳。直接(在HTML文档之外)添加与HTTP缓存相关的参数确实对我有用。

Python中使用web.py-web.header调用的示例代码如下。我有目的地编辑了我个人无关的实用程序代码。


    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()

此外,如果您使用.htaccess文件启用缓存,请确保重置该文件中的ExpiresDefault。

ExpiresDefault "access plus 0 seconds"

然后,可以使用ExpiresByType为要缓存的文件设置特定值:

ExpiresByType image/x-icon "access plus 3 month"

如果您的动态文件(如php等)被浏览器缓存,并且您无法找出原因,那么这可能也很有用。选中ExpiresDefault。

您可以在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");

当然,这可能不可能在整个网站上实现,但至少对于一些关键页面,您可以做到这一点。希望这有帮助。

我用这种方式解决了。

2个注意事项:

1) 服务器端事件不是在后退单击时触发的,而是javascript。

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>");
    }

其中“Login”是我的id值,注销后为-1(可以使用其他值,例如布尔值)。

然后在我的页面中添加了以下内容:(这是在单击后启动的)

<script type="text/javascript">
if (getCookie('<%= Session.SessionID %>') < 0)
        {
            if (history.length > 0)
            {
                history.go(+1);
            }
        }

</script>

没有别的。

使用此解决方案,仅在同一浏览器上的每个页面注销后,才在每个页面上启用反向单击。