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

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

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

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


当前回答

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

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

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

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

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

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

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

其他回答

免责声明:我强烈建议阅读@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);

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

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

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

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

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

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