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


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

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

  • Internet Explorer 6+
  • Firefox 1.5+
  • Safari 3+
  • Opera 9+

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


1226
2017-09-08 12:08


起源


仅适用于ipad Safari,[this] [1]有帮助吗? [1]: stackoverflow.com/questions/24524248/... - Bakhshi
最简单的是使用:max-age = 10。这并不完美,因为页面将被缓存10秒。但它是那里最少的“标头意大利面”解决方案。此外,这有时会为使用反向代理的动态网站带来巨大的性能提升。 (您的慢速PHP脚本将每10秒调用一次,然后由反向代理缓存。每10秒一次比每位访问者好一次) - Hello World
另见 securityevaluators.com/knowledge/case_studies/caching - Pacerier
谢谢你提出这个好问题。为了好奇,可能会出现一些情况,使您发送一些数据,而不希望接收器保存它 “安全理由” 。你已经寄给他们了! - Accountant م
看到 stackoverflow.com/a/49925190/3748498 - pravdomil


答案:


介绍

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

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客户端(1997年引入了HTTP 1.1),那么您可以省略 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:

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:

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

使用Google 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元标记。仅当通过a从本地磁盘文件系统查看页面时,才会使用HTML元标记 file:// URL。也可以看看 W3 HTML规范第5.2.2章。如果不以编程方式指定它们,请注意这一点,因为Web服务器可以包含一些默认值。

一般来说,你最好  指定HTML元标记以避免启动者混淆,并依赖于硬HTTP响应标头。而且,特别是那些 <meta http-equiv> 标签是 无效 在HTML5中。只有 http-equiv 列出的值 HTML5规范 被允许。

验证实际的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路径或查询字符串中的某处使用某些文件版本标识符以强制在已更改的文件上重新下载。无论如何在文件下载时应用这些无缓存标头时,请注意通过HTTPS而不是HTTP提供文件下载时的IE7 / 8错误。有关详情,请参阅 IE无法下载foo.jsf。 IE无法打开这个网站。请求的网站不可用或无法找到


2126
2018-03-30 23:08



这似乎并不完整。我在IE 8上尝试了这个解决方案,发现当你点击后退按钮时,浏览器会加载一个缓存版本。 - Mike Ottum
可能你的测试方法错了。也许页面已经在缓存中?也许标题不正确/重写?也许你在看错了请求?等等.. - BalusC
实际上,我确认这种方法不完整并导致IE8问题,或者至少在某些情况下。具体来说,当使用IE8通过SSL获取资源时,IE8将拒绝第二次获取资源(根本不会获取资源,或者在第一次尝试之后,取决于使用的标头)。看到 EricLaw的博客, 例如。 - haylem
我想补充一点,这基本上就是美国银行所做的事情。如果你查看他们的响应头并将其转换为aspx,他们正在做:Response.AppendHeader(“Cache-Control”,“no-cache,no-store,must-revalidate”); Response.AppendHeader(“Expires”,“Thu,1994年12月1日16:00:00 GMT”);我想,如果它对他们来说足够好,那对我来说已经足够了。 - John
@John:那个expires头文件正好是示例值 HTTP 1.0规范。它有效,但是完全采用那个时间戳有点荒谬。 - BalusC


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

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

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

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

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

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

  • 必须 交付 HTTPS否则这个缓存破坏将不可靠。另外,如果您没有使用HTTPS,那么您的页面很容易受到许多其他方式的登录窃取。
  • 你必须发送 Cache-Control: no-store, must-revalidate (一些浏览器观察 no-store 并且有些观察 must-revalidate

决不 需要任何:

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

如果需要,可以添加:

  • no-cache 要么 max-age=0,这将使资源(URL)“陈旧”,并要求浏览器检查服务器是否有更新的版本(no-store已经意味着这更强大了)。
  • Expires 有HTTP / 1.0客户端的过去日期(尽管如此) 真实 这些天,仅HTTP / 1.0客户端完全不存在。

奖金: 新的HTTP缓存RFC


205
2017-08-29 16:50



在加载时间方面,这会对网站的性能产生任何副作用吗? no-store,no-cache,must-revalidate如何影响性能? - Raman Ghai
@RamanGhai禁用缓存通常会损害性能(以及您提到的禁用缓存的所有3个选项)。它可能使CDN和ISP代理(例如,移动运营商常用)无效。它不会损害新用户的第一次加载(除了代理问题),但随后的导航可能会慢得多。 - Kornel
@porneL你声明我们必须发送 Cache-Control: must-revalidate。为什么不发送 Cache-Control: no-cache 以来 no-cache 已暗示 must-revalidate? w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1 - Pacerier
@Pacerier的关系 no-cache 同 must-revalidate 对于缓存是正确的,但后退历史记录不是缓存。 浏览器特例明确 must-revalidate 控制历史行为。 - Kornel
@porneL,嗯是否有一个支持RFC,表明这是所期望的行为? - Pacerier


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

在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="">
    失败:歌剧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="">
    失败:歌剧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="">
    失败:歌剧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
    失败:歌剧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="">
    失败:歌剧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="">
    失败:歌剧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


82
2018-06-15 02:40



我知道这是几年前发布的,但这是一个有趣的阅读。这个问题一直让我疯狂了几个月,身体似乎真的知道如何处理缓存控制。我见过几个人用过 <body onunload=""> 但它似乎更像是解决实际问题的方法。我尝试过使用.htaccess并以这种方式修改标题,如果我使用HTTPS应该以这种方式工作吗?这主要是狩猎问题最多的问题。 - Jordan
@Jordan,根据上面的日志,如果你有HTTPS然后添加 Cache-Control: no-store 会做的伎俩。 <body onunload=""> 仅在没有HTTPS时才需要。 - Pacerier


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

24
2018-01-14 23:35



对于web.config,我会稍微修改一下,只为那些我们知道动态加载/使用requirejs的脚本应用自定义标头。假设您的脚本位于客户端文件夹中:<location path =“client”> ..... </ location> - Ibrahim ben Salah
谁可能想知道什么 web.conf 是:它是一个主要的设置和配置文件 ASP.NET Web应用程序。它是一个位于根目录中的XML文档。 (维基)。 - another


我发现此页面上的所有答案仍然存在问题。特别是,我注意到当你通过点击后退按钮访问它时,它们都不会阻止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时,这些标题会导致从服务器请求页面直接在地址栏中。这涵盖了 99% 截至2010年1月使用的所有浏览器。

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

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


22
2017-09-08 12:11



这适用于IE8的后退按钮!! 在尝试其他所有建议中的所有内容后,添加“Vary:*”标题显然是唯一可以强制IE8在用户按下后退按钮时重新加载页面的内容。和这个 不 在HTTP / 1.1服务器上工作。 - CoreDumpError
结合BarlusC建议的标题,加上一个JS片段,当onPageShow事件触发“持久”属性(Safari需要)时调用window.location.reload(), 一切 我已成功测试的浏览器在用户使用“返回”按钮时强制从服务器重新加载。 - CoreDumpError
@CoreDumpError,哦,你不应该假设启用了JavaScript。 - Pacerier
@Chris,刚刚测试过。它在Safari 5.1.7和Opera上不起作用...... - Pacerier
@Pacerier当我在2010年写下答案的时候,这就是当时Safari和Opera的最新版本,我们的服务器将自己标识为HTTP 1.0服务器。不幸的是,我没有任何方法可以轻松地对此进行测试,所以我不能对这些浏览器的最新版本做出任何明确的决定。 - Chris Vasselli


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

在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


18
2017-09-17 14:18



@bart:更麻烦的是,1997年7月26日是星期六,而不是星期一...... - Cᴏʀʏ
Cache-Control: no-cache 和 Cache-Control: private 冲突 - 你永远不应该在一起:前者告诉浏览器和代理根本不要缓存,后者告诉代理不要缓存,但让浏览器拥有自己的私有副本。我不确定浏览器会遵循哪种设置,但浏览器和版本之间不太可能保持一致。 - Keith
@Edward,经过测试,无法在Safari 5.1.7和Opera上运行 - Pacerier
不要使用预检和后检查。 blogs.msdn.com/b/ieinternals/archive/2009/07/20/... - EricLaw
这对我不起作用 - 使用asp.net 4.5代码运行但不会产生所需的结果。我不得不遵循这个: stackoverflow.com/questions/22443932/... - Andy


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

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


8
2017-09-18 10:36



这是为什么你需要超越规范的一个很好的例子。如果规格总是很清晰,那么像StackOverflow这样的网站就没那么重要了。从 微软  为了与HTTP 1.0服务器向后兼容,Internet Explorer支持HTTP Pragma:no-cache标头的特殊用法。如果客户端通过安全连接(https://)与服务器通信,并且服务器返回带有响应的Pragma:no-cache标头,则Internet Explorer不会缓存响应。 - michaelok
@michaelok:你的引用是有效的,但是错过了更大的一点 - 设置一个合适的Cache-Control / Expires并且你不需要pragma。 - EricLaw


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

查看更完整的文档 这里


7
2018-06-13 15:23



这充满了神话。预检查和后检查仅限IE,仅与缓存的响应相关,0值为无操作。 max-stale是代理请求标头,而不是服务器响应标头。 Expires只接受单个值。多个将导致忽略此标头。 - Kornel
@porneL,你会提交一个正确处理这些神话的竞争性答案吗? - Oddthinking
@Oddthinking,看起来像 stackoverflow.com/questions/49547/... 是一个竞争的答案。 - Mike Ottum
@Steven,刚刚测试过。它在Safari 5.1.7和Opera上不起作用...... - Pacerier
@Pacerier是的,正如我在免责声明中所说,使用BalusC的答案。 - Steven Oxley