关于http:如何在所有浏览器中控制网页缓存?

How to control web page caching, across all browsers?

我们的调查表明,并非所有浏览器都以统一的方式遵守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:

Chrome developer toolset HTTP traffic monitor showing HTTP response headers on stackoverflow.com

我也要在文件下载时设置这些头文件

首先,这个问题和答案的目标是"网页"(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-checkpre-check-这是仅适用于可计算资源的指令。
  • 发送同一个标题两次或分十二部分。一些PHP代码片段实际上替换了前面的头,结果只发送了最后一个。

如果需要,可以添加:

  • no-cachemax-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>();

    一定要在后面加上这个

    1
    app.UseStaticFiles();


    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事件处理程序属性:

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