我们如何在所有浏览器中控制网页缓存?


1552

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

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

  • Internet Explorer 6+
  • Firefox 1.5以上
  • Safari 3+
  • 歌剧9+

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


仅用于iPad Safari,[this] [1]有帮助吗?[1]:stackoverflow.com/questions/24524248/...
Bakhshi

最简单的方法是:max-age = 10。这不是完美的,因为页面将被缓存10秒钟。但这是那里最少的“标头意大利面”解决方案。此外,有时在使用反向代理的动态网站上可以大大提高性能。(您的缓慢php脚本将每10秒被调用一次,然后将由反向代理缓存。每10秒一次比每个访问者一次要好得多)
Hello World


3
谢谢你提出这个大问题。出于好奇,可能是什么情况使您发送一些数据而又出于“安全原因”不希望接收器保存数据。您已经发送了!
会计师م17年

1
@Accountant:在他的情况下,用户已注销。谁可以保证该User-Agent上的下一个人工用户将是刚刚注销的人?
Fabien Haddadi

Answers:


2578

介绍

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

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代理。

如果仅通过HTTPS提供页面时,如果您不在意IE6及其缓存中断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-ControlExpires仅依赖它。

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或Python / Flask:

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:

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

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

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

使用HTML4:

<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响应标头

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

通常,最好不要指定HTML元标记,以免引起初学者的困惑并依赖硬HTTP响应标头。此外,尤其是这些<meta http-equiv>标记在HTML5 中无效。仅允许HTML5规范http-equiv列出的值。

验证实际的HTTP响应标头

要验证彼此,可以在webbrowser开发人员工具集的HTTP流量监视器中查看/调试它们。您可以通过在Chrome / Firefox23 + / IE9 +中按F12,然后打开“网络”或“网络”标签面板,然后单击感兴趣的HTTP请求以发现有关HTTP请求和响应的所有详细信息,来到达那里。在下面的截图是从Chrome中:

Chrome开发人员工具集HTTP流量监视器,在stackoverflow.com上显示HTTP响应标头

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

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


16
这似乎并不完整。我在IE 8上尝试了此解决方案,发现单击后退按钮时浏览器将加载缓存的版本。
Mike Ottum

16
您的测试方法很可能是错误的。页面可能已经在缓存中了吗?标题可能不正确/被覆盖吗?也许您看错了请求?等等
BalusC

8
实际上,我确认这种方法是不完整的,并且至少在某些情况下会导致IE8出现问题。具体来说,当使用IE8通过SSL获取资源时,IE8将拒绝第二次获取资源(完全或第一次尝试后,取决于所使用的标头)。例如,请参阅EricLaw的博客
haylem 2012年

21
我想补充一点,这基本上就是美国银行所做的事情。如果您查看他们的响应标头并将其转换为aspx,他们就会这样做:Response.AppendHeader(“ Cache-Control”,“ no-cache,no-store,必须重新验证”); Response.AppendHeader(“ Expires”,“星期四,1994年12月1日星期四16:00:00 GMT”); 我认为,如果对他们足够好,对我也足够。
约翰

8
@John:过期标头正是HTTP 1.0规范中的示例值。它可以工作,但是确切地使用那个时间戳有点荒谬。
BalusC

244

(嘿,大家:请不要随便复制并粘贴所有可以找到的标头)

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

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

在旧的HTTP规范中,措词甚至更强,明确告诉浏览器对于后退按钮历史记录忽略高速缓存指令。

回到应该回到过去(到时候用户登录)。它不会向前导航到先前打开的URL。

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

  • 页面必须通过 HTTPS,否则这种缓存清除将不可靠。另外,如果您不使用HTTPS,则您的页面很容易受到其他多种方式的窃取。
  • 您必须发送Cache-Control: no-store, must-revalidate(某些浏览器遵守no-store,有些则遵守must-revalidate

永远不需要:

  • <meta>带有缓存头的文件-根本不起作用。完全没用。
  • post-check/ pre-check—这是仅适用于achable的IE指令资源。
  • 发送相同的标头两次或十几个部分。一些PHP片段实际上替换了先前的标头,导致仅发送了最后一个。

如果需要,可以添加:

  • no-cachemax-age=0,这将使资源(URL)“陈旧”,并要求浏览器向服务器检查是否有较新的版本(no-store已经暗示它会更强大)。
  • ExpiresHTTP / 1.0客户端的日期为过去的日期(尽管现在完全不存在真正的 HTTP / 1.0客户端)。

奖励:新的HTTP缓存RFC


1
就加载时间而言,这会对网站的性能产生副作用吗?无存储,无缓存,必须重新验证如何影响性能?
拉曼·盖

@RamanGhai禁用缓存通常会影响性能(您提到的所有3个选项都禁用缓存)。这可能会使CDN和ISP代理(例如,移动运营商通常使用的代理)无效。它不会损害新用户的首次加载(除了代理问题),但随后的导航可能会慢很多。
Kornel

@porneL,您声明我们必须发送Cache-Control: must-revalidate。为什么不发送Cache-Control: no-cacheno-cache已经暗示了must-revalidatew3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1
Pacerier,2013年

3
@Pacerier的关系no-cachemust-revalidate是真正的缓存,但回到历史不是一个缓存。浏览器的特殊情况是显式的,must-revalidate以控制历史行为
Kornel

@ porneL,Hmm是否提供支持的RFC,指出这是所需的行为?
Pacerier

103

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

在Chrome(v28.0.1500.95 m)中,我们只能通过进行此操作Cache-Control: no-store

在FireFox(v23.0.1)中,以下任何一种均可工作:

  1. Cache-Control: no-store

  2. Cache-Control: no-cache (仅https)

  3. Pragma: no-cache (仅https)

  4. Vary: * (仅https)

在Opera(v12.15)中,我们只能通过Cache-Control: must-revalidate(仅https)来执行此操作。

在Safari(v5.1.7,7534.57.2)中,以下任何一种均可使用:

  1. Cache-Control: no-store
    <body onunload=""> 在HTML

  2. Cache-Control: no-store (仅https)

在IE8(v8.0.6001.18702IC)中,以下任何一种均可工作:

  1. Cache-Control: must-revalidate, max-age=0

  2. Cache-Control: no-cache

  3. Cache-Control: no-store

  4. Cache-Control: must-revalidate
    Expires: 0

  5. Cache-Control: must-revalidate
    Expires: Sat, 12 Oct 1991 05:00:00 GMT

  6. Pragma: no-cache (仅https)

  7. 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:

  1. 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

  2. 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

  3. 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

  4. 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

  5. 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

  6. 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

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

  8. 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

  9. Cache-Control: no-store
    失败:Safari 5.1.7,Opera 12.15
    成功:Chrome 28,FireFox 23,IE8

  10. Cache-Control: no-store
    <body onunload="">
    失败:Opera 12.15
    成功:Chrome 28,FireFox 23,IE8,Safari 5.1.7

  11. Cache-Control: no-cache
    失败:Chrome 28,FireFox 23,Safari 5.1.7,Opera 12.15
    成功:IE8

  12. Vary: *
    失败:Chrome 28,FireFox 23,IE8,Safari 5.1.7,Opera 12.15
    成功:无

  13. Pragma: no-cache
    失败:Chrome 28,FireFox 23,IE8,Safari 5.1.7,Opera 12.15
    成功:无

  14. 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

  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,FireFox 23,Safari 5.1.7,Opera 12.15
    成功:IE8

  16. Cache-Control: must-revalidate, max-age=0
    失败:Chrome 28,FireFox 23,Safari 5.1.7,Opera 12.15
    成功:IE8

  17. Cache-Control: must-revalidate
    Expires: 0
    失败:Chrome 28,FireFox 23,Safari 5.1.7,Opera 12.15
    成功:IE8

  18. 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

  19. 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:

  1. 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
    成功:无

  2. 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
    成功:无

  3. Vary: *
    失败:Chrome 28,Safari 5.1.7,Opera 12.15
    成功:FireFox 23,IE8

  4. Pragma: no-cache
    失败:Chrome 28,Safari 5.1.7,Opera 12.15
    成功:FireFox 23,IE8

  5. Cache-Control: no-cache
    失败:Chrome 28,Safari 5.1.7,Opera 12.15
    成功:FireFox 23,IE8

  6. 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

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

  8. 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

  9. Cache-Control: must-revalidate
    失败:Chrome 28,FireFox 23,IE8,Safari 5.1.7
    成功:Opera 12.15

  10. Cache-Control: private, must-revalidate, proxy-revalidate, s-maxage=0
    <body onunload="">
    失败:Chrome 28,FireFox 23,IE8,Safari 5.1.7
    成功:Opera 12.15

  11. Cache-Control: must-revalidate, max-age=0
    失败:Chrome 28,FireFox 23,Safari 5.1.7
    成功:IE8,Opera 12.15

  12. 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

  13. 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

  14. Cache-Control: no-store
    失败:Opera 12.15
    成功:Chrome 28,FireFox 23,IE8,Safari 5.1.7

  15. 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

  16. 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

  17. 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

  18. Cache-Control: must-revalidate
    Expires: 0
    失败:Chrome 28,FireFox 23,Safari 5.1.7,
    成功:IE8,Opera 12.15

  19. 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

  20. 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

  21. 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

  22. 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

  23. Cache-Control: no-store, must-revalidate
    失败:无
    成功:Chrome 28,FireFox 23,IE8,Safari 5.1.7,Opera 12.15


3
我知道这是几年前发布的,但是读起来很有趣。这个问题已经让我抓狂了几个月了,身体似乎真的知道如何处理缓存控制。我见过一些人使用,<body onunload="">但似乎更像解决实际问题的一种方法。我尝试使用.htaccess并以这种方式修改标头,如果使用HTTPS,它应该以这种方式工作吗?问题最多的主要是野生动物园。
乔丹

4
@Jordan,如果您使用HTTPS,则按照上面的日志进行操作,然后添加即可解决问题Cache-Control: no-store<body onunload="">仅当您没有HTTPS时才需要。
Pacerier,2015年

37

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

对于web.config,我将做一些修改以仅将自定义标头应用于我们知道动态加载/使用requirejs的那些脚本。假设您的脚本在客户端文件夹中找到:<location path =“ client”> ..... </ location>
Ibrahim ben Salah 2015年

对于谁可能会想知道是什么web.conf:它是ASP.NETWeb应用程序的主要设置和配置文件。它是一个XML文档,位于根目录中。(Wiki)。

27

我发现此页面上的所有答案仍然存在问题。特别是,我注意到当您通过单击“后退”按钮访问IE8时,它们都无法阻止IE8使用该页面的缓存版本。

经过大量的研究和测试,我发现我真正需要的仅有两个标头是:

缓存控制:不存储
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时,这些标题导致从服务器请求页面直接在地址栏中。约占99%截至2010年1月,使用中的所有浏览器的。

在IE6和Opera 9-10上,单击“后退”按钮仍会导致加载缓存的版本。在我测试过的所有其他浏览器上,它们确实从服务器获取了一个新版本。到目前为止,我还没有找到任何可以使这些浏览器在您按下“后退”按钮时不返回页面的缓存版本的标头集。

更新: 写下此答案后,我意识到我们的Web服务器将自己标识为HTTP 1.0服务器。我列出的标头是正确的标头,以便浏览器不会缓存来自HTTP 1.0服务器的响应。对于HTTP 1.1服务器,请查看BalusC的答案


4
这适用于IE8的后退按钮!!在尝试所有其他建议中的所有内容之后,添加“ Vary:*”标头显然是唯一可以迫使IE8在用户按下“后退”按钮时重新加载页面的东西。这确实适用于HTTP / 1.1服务器。
coredumperror13年

结合BarlusC建议的标头,以及当onPageShow事件使用“ persisted”属性(Safari需要)触发时,调用window.location.reload()的JS代码段,我测试过的每个浏览器都成功地强制从用户使用“后退”按钮时的服务器。
coredumperror13年

1
@CoreDumpError,哦,您不应该假设已启用JavaScript。
Pacerier

@Pacerier在我2010年写答案时,此方法适用于Safari和Opera的最新版本,我们的服务器将其自身标识为HTTP 1.0服务器。不幸的是,我没有任何方法可以轻松地对此进行测试,因此我无法对这些浏览器的最新版本发表任何明确的定义。
克里斯·瓦塞利

您测试过的浏览器版本是什么?
Pacerier,2013年

21

经过一些研究,我们得出了以下标题列表,这些标题似乎涵盖了大多数浏览器:

在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", "Mon, 26 Jul 1997 05:00:00 GMT"); // HTTP 1.0 

发现于:http : //forums.asp.net/t/1013531.aspx


35
@bart:更麻烦的又是7月份的1997年26号是星期六,而不是星期一......
Cᴏʀʏ

5
Cache-Control: no-cacheCache-Control: private冲突-永远都不要在一起:前者告诉浏览器和代理根本不要缓存,后者告诉代理不要缓存,但让浏览器保留自己的私有副本。我不确定浏览器将遵循哪个设置,但是浏览器和版本之间不太可能保持一致。
基思2012年

不要使用预检查和后检查。blogs.msdn.com/b/ieinternals/archive/2009/07/20/...
EricLaw

这对我不起作用-使用asp.net 4.5可以运行代码,但不会产生所需结果。我必须遵循以下规则:stackoverflow.com/questions/22443932/…–
Andy

8

响应中使用pragma标头是一个妻子的故事。RFC2616仅将其定义为请求标头

http://www.mnot.net/cache_docs/#PRAGMA


4
这是为什么您需要超出规格的一个很好的例子。如果规格始终清晰明了,那么对于StackOverflow这样的网站就没有多大意义了。来自Microsoft 出于与HTTP 1.0服务器向后兼容的目的,Internet Explorer支持HTTP Pragma的特殊用法:no-cache标头。如果客户端通过安全连接(https://)与服务器通信,并且服务器返回带有响应的Pragma:no-cache标头,则Internet Explorer不会缓存响应。
michaelok

@michaelok:您的引用是有效的,但没有抓住更大的要点-设置适当的Cache-Control / Expires,并且您不需要编译。
EricLaw 2015年

8

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

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


14
这充满了神话。pre-check和post-check仅用于IE,仅与缓存的响应相关,0值表示无操作。max-stale是代理请求标头,而不是服务器响应标头。过期仅接受单个值。不止一个将导致忽略此标头。
Kornel

1
@porneL,您会提交一个正确解决这些神话的竞争性答案吗?
奇怪的

@Oddthinking,看起来像stackoverflow.com/questions/49547/…是一个相互竞争的答案。
Mike Ottum 2010年

@Pacerier是的,正如我在免责声明中所述,请使用BalusC的答案。
史蒂芬·奥克斯利2013年

8

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

我建议使用Microsoft.Net.Http.Headers.HeaderNames中的常量代替字符串文字“ Cache-Controls”,“ Pragma”和“ Expires”。
Victor Sharovatov

7

这些指令不会减轻任何安全风险。它们的真正目的是迫使UA刷新易失性信息,而不是阻止UA保留信息。看到类似的问题。至少,不能保证任何路由器,代理等也不会忽略缓存指令。

更积极的一点是,有关物理访问计算机,软件安装等方面的策略将使您在安全性方面领先于大多数公司。如果这些信息的使用者是公众的成员,那么您唯一能做的就是帮助他们了解,一旦信息进入他们的机器,那台机器就是他们的责任,而不是您责任。



6

HTTP 1.1的RFC表示正确的方法是为以下项添加HTTP标头:

缓存控制:无缓存

如果较旧的浏览器不正确符合HTTP 1.1,则可能会忽略此设置。对于那些,您可以尝试标题:

语法:无缓存

这也应该适用于HTTP 1.1浏览器。


1
规范指出,未经重新验证,不得重用响应。Cache-Control:no-store是官方方法,它指示响应甚至没有存储在缓存中。
AnthonyWJones

6

通常在1995年将修改后的http标头设置为某个日期即可。

这是一个例子:

过期:1995年11月15日星期三格林尼治标准时间
上次修改时间:1995年11月15日,星期三,格林尼治标准时间
缓存控制:无缓存,必须重新验证

1
设置长久的Last-Modified对缓存没有影响,除了由于启发式重新验证而使缓存的响应使用更长的时间之外。
EricLaw 2015年

6

标头函数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);

11
这显然是错误的。对Expires,Cache-control和Pragma的header()的第二次调用完全覆盖了先前设置的值。
Kornel

1
@porneL:否,请勿覆盖先前设置的值,因为他将false作为第二个参数传递,告诉不要覆盖先前的值。
Julien Palard

1
@JulienPalard在我发表评论后,答案已被编辑。仍然没有多大意义。
Kornel

如果要在IE 9之前的版本中工作,请不要发送多个Cache-Control标头。永远不要发送预检查或后检查。blogs.msdn.com/b/ieinternals/archive/2009/07/20/...
EricLaw

6

如果您遇到IE6-IE8通过SSL和MS Office文件使用cache:no-cache标头(和类似值)的下载问题,则可以使用cache:private,no-store标头并在POST请求时返回文件。有用。


6

就我而言,我用这个解决了chrome的问题

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

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


代码段也解决了我的mozilla 19.x浏览器问题。autocomplete =“ off”。谢谢。
萨蒂亚

5

接受的答案似乎不适用于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-controlno-cache,第二行添加其他属性no-store, must-revalidate


这对我Response.Cache.SetAllowResponseInBrowserHistory(false); Response.Cache.SetCacheability(HttpCacheability.NoCache); Response.Cache.SetNoStore(); Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
有用

4

通过设置Pragma,我在所有浏览器中获得了最好,最一致的结果:no-cache


4

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

<body onunload=""> 

此黑客显然破坏了Safari中的后退缓存:单击“后退”按钮时是否存在跨浏览器的onload事件?


不错,我已经测试过了,它实际上可以在Safari(5.1.7)上运行,但不能在Opera上运行。
Pacerier 2013年

4

另外,出于良好的考虑,如果您使用它来启用缓存ExpiresDefault,请确保将.htaccess文件中的重置。

ExpiresDefault "access plus 0 seconds"

之后,您可以用来ExpiresByType为要缓存的文件设置特定的值:

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

如果您的动态文件(例如php等)正在由浏览器缓存,这也可能会派上用场,而您不知道为什么。检查ExpiresDefault


3

除了标题之外,还可以考虑通过https服务您的页面。默认情况下,许多浏览器不会缓存https。


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

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

2

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


0

我只想指出,如果有人想防止仅缓存动态内容,则应以编程方式添加这些其他标头。

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

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

还有另一个警告。使用HttpResponse类中的ClearHeaders方法时要小心。如果您不计后果地使用它,可能会给您带来一些挫伤。就像它给了我。

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

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

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

0

我没有运气 <head><meta>。实际上,直接添加HTTP缓存相关参数(在HTML文档之外)对我确实有用。

web.header以下是使用web.py 调用的Python示例代码。我故意编辑了与个人无关的实用程序代码。

    导入网站
    导入系统
    进口个人工具

    myname =“ main.py”

    网址=(
        '/','main_class'
    )

    main = web.application(urls,globals())

    render = web.template.render(“ templates /”,base =“ layout”,cache = False)

    类main_class(object):
        def GET():
            web.header(“缓存控制”,“无缓存,无存储,必须重新验证”)
            web.header(“ Pragma”,“ no-cache”)
            web.header(“ Expires”,“ 0”)
            返回render.main_form()

        def POST(自己):
            msg =“已发布:”
            形式= web.input(功能=无)
            web.header(“缓存控制”,“无缓存,无存储,必须重新验证”)
            web.header(“ Pragma”,“ no-cache”)
            web.header(“ Expires”,“ 0”)
            返回render.index_laid_out(问候= msg + form.function)

    如果__name__ ==“ __main__”:
        nargs = len(sys.argv)
        #确保python程序名称后有足够的参数
        如果nargs!= 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)失败(不是整数)”,我的名字,sys.argv [1])
        # 一切都很好!
        JUST-LOG(“%s:在端口%d上运行”,myname,tcp_port)
        web.httpserver.runsimple(main.wsgifunc(),(“ localhost”,tcp_port))
        main.run()


网站上已有多年的答案了吗?
马丁·图尔诺伊

META指令可在Internet Explorer和Edge 18及更低版本中使用。现代浏览器不支持它们。crbug.com/2763
EricLaw

0

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

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

摘要,根据这篇文章,仅Cache-Control: no-store适用于Chrome,Firefox和IE。IE接受其他控件,但Chrome和Firefox不接受。该链接是一本很好的阅读文章,其中包含缓存的历史记录和概念证明文档。


0

不知道我的答案听起来是否简单而愚蠢,也许很久以前您就已经知道了,但是由于阻止某人使用浏览器后退按钮查看您的历史页面是您的目标之一,因此您可以使用:

window.location.replace("https://www.example.com/page-not-to-be-viewed-in-browser-history-back-button.html");

当然,这可能无法在整个站点上实现,但是至少对于某些关键页面,您可以这样做。希望这可以帮助。


-1

您可以使用位置块来设置单个文件,而不是整个应用程序在IIS中进行缓存

 <location path="index.html">
    <system.webServer>
      <httpProtocol>
        <customHeaders>
          <add name="Cache-Control" value="no-cache" />
        </customHeaders>
      </httpProtocol>
    </system.webServer>
  </location>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.