ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

互联网浏览器 6+

火狐 1.5+

野生动物园 3+

歌剧 9+

铬合金

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

仅适用于 ipad Safari,[this][1] 有帮助吗? [1]:stackoverflow.com/questions/24524248/…
最简单的是使用: max-age=10 。这并不完美,因为页面将被缓存 10 秒。但它是目前最少的“标题意大利面条”解决方案。此外,这有时会在使用反向代理的动态网站上提供很大的性能提升。 (您的慢速 php 脚本将每 10 秒调用一次,然后由反向代理缓存。每 10 秒一次比每个访问者一次要好)
谢谢你的好问题。出于好奇,可能是什么情况使您发送一些数据而不想让接收者出于“安全原因”保存它。你已经寄给他们了!
@Accountant:在他的场景中,用户已经注销。谁能保证该 User-Agent 上的下一个人类用户将是刚刚注销的人?

4
45 revs, 25 users 55%

介绍

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

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

如果您在仅使用 no-store 的 HTTPS 上提供页面时不关心 IE6 及其损坏的缓存,那么您可以省略 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-Control 并仅依赖 Expires

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

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

如果指定了上述 Cache-Control 参数,则其他 Cache-Control 参数(例如 max-age)无关紧要。如果您确实希望缓存请求,此处包含在大多数其他答案中的 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:

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/金字塔:

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

使用围棋:

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

重要的是要知道,如果通过 HTTP 连接提供 HTML 页面,并且 both HTTP 响应标头和 HTML <meta http-equiv> 标记中存在标头,那么 HTTP 响应中指定的标头header 将优先于 HTML 元标记。只有在通过 file:// URL 从本地磁盘文件系统查看页面时,才会使用 HTML 元标记。另见W3 HTML spec chapter 5.2.2。当您不以编程方式指定它们时请注意这一点,因为网络服务器可以包含一些默认值。

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

验证实际的 HTTP 响应标头

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

https://i.stack.imgur.com/fSnXH.png

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

首先,这个问答针对的是“网页”(HTML页面),而不是“文件下载”(PDF、zip、Excel等)。您最好将它们缓存起来,并在 URI 路径或查询字符串的某处使用某些文件版本标识符来强制重新下载已更改的文件。无论如何,当在文件下载上应用那些无缓存标头时,当通过 HTTPS 而不是 HTTP 提供文件下载时,请注意 IE7/8 错误。有关详细信息,请参阅IE cannot download foo.jsf. IE was not able to open this internet site. The requested site is either unavailable or cannot be found


这似乎并不完整。我在 IE 8 上尝试了这个解决方案,发现当你点击后退按钮时浏览器会加载一个缓存版本。
很可能您的测试方法是错误的。也许页面已经在缓存中?也许标题不正确/被覆盖?也许您正在查看错误的请求? ETC..
实际上,我确认这种方法是不完整的,并且会导致 IE8 出现问题,或者至少在某些情况下会出现问题。具体来说,当使用 IE8 通过 SSL 获取资源时,IE8 将拒绝第二次获取资源(完全拒绝,或者在第一次尝试后,取决于使用的标头)。例如,参见 EricLaw's blog
我想补充一点,这基本上就是美国银行所做的。如果您查看他们的响应标头并将其转换为 aspx,他们正在这样做: Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); Response.AppendHeader("Expires", "Thu, 01 Dec 1994 16:00:00 GMT");我想,如果这对他们来说足够好,那对我来说就足够了。
@John:过期标头正是 HTTP 1.0 specification 中的示例值。它有效,但准确地采用那个时间戳有点荒谬。
F
Farzad Karimi

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

首先,Back button history is not a cache

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

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

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

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

页面必须通过 HTTPS 传递,否则,这种缓存清除将不可靠。另外,如果您不使用 HTTPS,那么您的页面很容易以许多其他方式窃取登录信息。

您必须发送 Cache-Control: no-store, must-revalidate(一些浏览器观察 no-store 和一些观察 must-revalidate)

你永远不需要任何:

带有缓存头——它根本不起作用。完全没用。

post-check/pre-check — 这是一个仅适用于可缓存资源的 IE 指令。

发送相同的标题两次或十几个部分。那里的一些 PHP 片段实际上替换了以前的标头,导致只发送最后一个标头。

如果你愿意,你可以添加:

no-cache 或 max-age=0,这将使资源(URL)“陈旧”,并要求浏览器与服务器检查是否有更新的版本(no-store 已经暗示这一点更强大)。

HTTP/1.0 客户端在过去的某个日期过期(尽管现在完全不存在真正的仅 HTTP/1.0 客户端)。

奖金:The new HTTP caching RFC


就加载时间而言,这会对网站的性能产生任何副作用吗? no-store , no-cache , must-revalidate 如何影响性能?
@RamanGhai 禁用缓存通常会损害性能(以及您提到的所有 3 个选项都禁用缓存)。它可能使 CDN 和 ISP 代理(例如移动运营商常用的)无效。它不会伤害新用户的首次加载(除了代理问题),但随后的导航可能会慢很多。
@porneL 您声明我们必须发送 Cache-Control: must-revalidate。为什么不发送 Cache-Control: no-cache,因为 no-cache 已经暗示 must-revalidatew3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1
@Pacerier no-cachemust-revalidate 的关系对于缓存是正确的,但回溯历史记录不是缓存。 Browsers special-case explicit must-revalidate to control history behavior
@porneL,嗯,是否有支持 RFC 说明这是所需的行为?
R
Ritesh

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

在 Chrome (v28.0.1500.95 m) 中,我们只能通过 Cache-Control: no-store 做到这一点。

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

Cache-Control: no-store Cache-Control: no-cache (https only) Pragma: no-cache (https only) Vary: * (https only)

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

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

缓存控制:无存储 在 html 缓存控制:无存储(仅限 https)

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

Cache-Control: must-revalidate, max-age=0 Cache-Control: no-cache Cache-Control: no-store Cache-Control: must-revalidate Expires: 0 Cache-Control: must-revalidate Expires: Sat, 12 Oct 1991 05:00:00 GMT Pragma:无缓存(仅限 https) 变化:*(仅限 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:

Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0 Expires: 0 Pragma: no-cache Vary: * 失败:Opera 12.15 成功:Chrome 28、FireFox 23、IE8、Safari 5.1.7 缓存控制:private、no-cache、no-store、must-revalidate、max-age=0、proxy-revalidate、s-maxage =0 过期时间:星期六,1991 年 10 月 12 日 05:00:00 GMT 编译指示:无缓存 变化:* 失败:Opera 12.15 成功:Chrome 28、FireFox 23、IE8、Safari 5.1.7 缓存-控制:private、no-cache、no-store、must-revalidate、max-age=0、proxy-revalidate、s-maxage=0 Expires: 0 Pragma: no-cache Vary: * Fail: Safari 5.1.7, Opera 12.15 成功:Chrome 28、FireFox 23、IE8 缓存控制:private、no-cache、no-store、must-revalidate、max-age=0、proxy-revalidate、s-maxage=0 过期时间:1991 年 10 月 12 日星期六05:00:00 GMT Pragma: no-cache Vary: * Fail: Safari 5.1.7, Opera 12.15 Success: Chrome 28, FireFox 23, IE8 Cache-Control: private, no-cache, must-revalidate, max-age= 0,代理重新验证,s-maxa ge=0 Expires: 0 Pragma: no-cache Vary: * Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15 Success: IE8 Cache-Control: private, no-cache, must -revalidate,max-age=0,proxy-revalidate,s-maxage=0 过期:星期六,1991 年 10 月 12 日 05:00:00 GMT 编译指示:无缓存变化:* 失败: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=0 Expires: 0 Pragma: no-缓存变化:* 失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15 成功:IE8 缓存控制:私有、无缓存、必须重新验证、max-age=0、代理-revalidate, s-maxage=0 过期时间:1991 年 10 月 12 日星期六 05:00:00 GMT 编译指示:无缓存 变化:* 失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15 成功:IE8 缓存控制:无存储失败:Safari 5.1.7、Opera 12.15 成功:Chrome 28、FireFox 23、IE8 缓存控制:无存储 失败:Opera 12.15 成功:Chrome 28、女ireFox 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 Success: none Pragma: no-cache Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15 Success: none Cache-Control: private, no-cache, must-revalidate, max-age= 0,代理重新验证,s-maxage=0 过期:1991 年 10 月 12 日星期六 05:00:00 GMT 编译指示:无缓存变化:* 失败:Chrome 28、FireFox 23、Safari 5.1。 7、Opera 12.15 Success: IE8 Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0 Expires: 0 Pragma: no-cache Vary: * 失败:Chrome 28、FireFox 23、Safari 5.1.7、Opera 12.15 成功:IE8 缓存控制:必须重新验证,max-age=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=0编译指示:no-cache 变化:* 失败:Chrome 28、FireFox 23、IE8、Safari 5.1.7、Opera 12.15 成功:无

HTTPS:

Cache-Control: private, max-age=0, proxy-revalidate, s-maxage=0 Expires: 0 失败: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15 成功:无缓存控制:私有,max-age=0,代理重新验证,s-maxage=0 过期:星期六,1991 年 10 月 12 日 05:00:00 GMT 失败:Chrome 28,FireFox 23, IE8、Safari 5.1.7、Opera 12.15 成功:无 变化:* 失败:Chrome 28、Safari 5.1.7、Opera 12.15 成功:FireFox 23、IE8 Pragma:无缓存 失败:Chrome 28、Safari 5.1.7、Opera 12.15成功:FireFox 23,IE8 缓存控制:无缓存失败:Chrome 28,Safari 5.1.7,Opera 12.15 成功:FireFox 23,IE8 缓存控制:私有,无缓存,max-age=0,代理重新验证, s-maxage=0 失败: Chrome 28, Safari 5.1.7, Opera 12.15 成功: FireFox 23, IE8 Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0 Expires : 0 Pragma: no-cache Vary: * Fail: Chrome 28, Safari 5.1.7, Opera 12.15 Success: FireFox 23, IE8 Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0 过期:1991 年 10 月 12 日星期六 05:00:00 GMT 编译指示:无缓存 变化:* 失败: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 失败:Chrome 28、 FireFox 23、IE8、Safari 5.1.7 成功:Opera 12.15 缓存控制:必须重新验证,max-age=0 失败:Chrome 28、FireFox 23、Safari 5.1.7 成功:IE8、Opera 12.15 缓存控制:私有, 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: * 失败:Chrome 28、Safari 5.1.7 成功:FireFox 23、IE8、Opera 12.15 缓存控制:私有、无缓存、必须重新验证、max-age=0、代理重新验证、s-maxage=0 过期: 0 Pragma: no-cache Vary: * Fail: Chrome 28, Safari 5.1.7 Success: FireFox 23, IE8, Opera 12.15 Cache-Control: no-store Fail: Opera 12.15 成功:Chrome 28、FireFox 23、IE8、Safari 5.1.7 缓存控制:private、no-cache、no-store、max-age=0、proxy-revalidate、s-maxage=0 Expires:0 Pragma:no -cache 变化:* 失败:Opera 12.15 成功:Chrome 28、FireFox 23、IE8、Safari 5.1.7 缓存控制:私有、无缓存、无存储、max-age=0、 proxy-revalidate, s-maxage=0 过期时间:星期六,1991 年 10 月 12 日 05:00:00 GMT Pragma: no-cache Vary: * Fail: Opera 12.15 Success: Chrome 28, FireFox 23, IE8 , Safari 5.1.7 Cache-Control: private, no-cache Expires: Sat, 12 Oct 1991 05:00:00 GMT Pragma: no-cache Vary: * Fail: Chrome 28, Safari 5.1.7, Opera 12.15 Success: FireFox 23、IE8 Cache-Control: must-revalidate Expires: 0 Fail: Chrome 28, FireFox 23, Safari 5.1.7, Success: IE8, Opera 12.15 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 缓存控制:私有,必须重新验证,max-age=0,代理重新验证,s-maxage=0 过期es: 0 失败: Chrome 28, FireFox 23, Safari 5.1.7, 成功: IE8, Opera 12.15 缓存控制: private, must-revalidate, max-age=0, proxy-revalidate, s -maxage=0 过期时间:星期六,1991 年 10 月 12 日 05:00:00 GMT 失败:Chrome 28,FireFox 23,Safari 5.1.7,成功:IE8,Opera 12.15 缓存控制:私有,必须-revalidate Expires: Sat, 12 Oct 12 05:00:00 GMT Pragma: no-cache Vary: * Fail: Chrome 28, Safari 5.1.7 Success: FireFox 23, IE8, Opera 12.15 Cache-Control: no-store, must -revalidate 失败:无成功:Chrome 28、FireFox 23、IE8、Safari 5.1.7、Opera 12.15


我知道这是几年前发布的,但读起来很有趣。这个问题已经让我发疯了几个月了,body 似乎真的知道如何处理缓存控制。我见过一些人使用 <body onunload="">,但它似乎更像是解决实际问题的一种方法。我尝试过使用 .htaccess 并以这种方式修改标头,如果我使用 HTTPS,它应该以这种方式工作吗?问题最严重的主要是野生动物园。
@Jordan,根据上面的日志,如果您有 HTTPS,那么添加 Cache-Control: no-store 就可以了。仅当您没有 HTTPS 时才需要 <body onunload="">
R
Royi Namir

我发现 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 的脚本应用自定义标头。假设您的脚本位于客户端文件夹中: .....
谁可能想知道 web.conf 是什么:它是 ASP.NET Web 应用程序的主要设置和配置文件。它是驻留在根目录中的 XML 文档。 (wiki)。
C
Community

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


这适用于 IE8 的后退按钮!在尝试了所有其他建议后,添加“Vary: *”标题显然是唯一可以在用户按下后退按钮时强制 IE8 重新加载页面的方法。这确实适用于 HTTP/1.1 服务器。
结合 BarlusC 建议的标头,加上一个在 onPageShow 事件触发时使用“持久”属性(Safari 需要)调用 window.location.reload() 的 JS 片段,我测试成功的每个浏览器都会强制从当用户使用返回按钮时服务器。
@CoreDumpError,哦,您不应该假设 JavaScript 已启用。
@Pacerier 在我 2010 年写答案时,这适用于当时最新版本的 Safari 和 Opera,我们的服务器将自己标识为 HTTP 1.0 服务器。不幸的是,我没有任何方法可以轻松地对此进行测试,因此我无法对这些浏览器的最新版本发表任何明确的意见。
您测试的浏览器版本是什么?
e
edwgiz

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

过期:1997 年 7 月 26 日星期六 05:00:00 GMT

缓存控制:无缓存、私有、必须重新验证、max-stale=0、post-check=0、pre-check=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


@bart:更麻烦的是,1997 年 7 月 26 日是星期六,而不是星期一……
Cache-Control: no-cacheCache-Control: private 冲突 - 你永远不应该将两者放在一起:前者告诉浏览器和代理根本不要缓存,后者告诉代理不要缓存,但让浏览器拥有自己的私有副本。我不确定浏览器会遵循哪种设置,但浏览器和版本之间不太可能保持一致。
不要使用预检查和后检查。 blogs.msdn.com/b/ieinternals/archive/2009/07/20/…
这对我不起作用 - 使用 asp.net 4.5 代码运行但不会产生所需的结果。我必须遵循这个:stackoverflow.com/questions/22443932/…
D
Dave Cheney

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

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


这是一个很好的例子,说明了为什么您需要超越规范。如果规格总是一清二楚,那么像 StackOverflow 这样的网站就没有多大意义了。从 Microsoft 为了向后兼容 HTTP 1.0 服务器,Internet Explorer 支持 HTTP Pragma 的特殊用法:no-cache 标头。如果客户端通过安全连接 (https://) 与服务器通信,并且服务器在响应中返回 Pragma: no-cache 标头,则 Internet Explorer 不会缓存响应。
@michaelok:你的参考是有效的,但错过了更大的一点——设置一个适当的缓存控制/过期,你不需要编译指示。
S
Steven Oxley

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

查看更完整的文档 here


这充满了神话。 pre-check 和 post-check 仅适用于 IE,仅与缓存的响应相关,0 值表示无操作。 max-stale 是代理请求标头,而不是服务器响应标头。 Expires 仅接受单个值。多个将导致此标头被忽略。
@porneL,您会提交正确处理这些神话的竞争答案吗?
@Oddthinking,看起来 stackoverflow.com/questions/49547/… 是一个竞争答案。
@Pacerier 是的,正如我在免责声明中所说,使用 BalusC 的答案。
E
Edson Medina

IE6 有问题

即使您使用“Cache-Control: no-cache”,具有“Content-Encoding: gzip”的内容也会始终被缓存。

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

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


k
kspearrin

对于 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”。
C
Community

这些指令不会减轻任何安全风险。它们实际上是为了迫使 UA 刷新易失性信息,而不是阻止 UA 保留信息。请参阅this similar question。至少,不能保证任何路由器、代理等也不会忽略缓存指令。

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


C
Chris Dail

HTTP 1.1 的 RFC 说正确的方法是为以下内容添加 HTTP 标头:

缓存控制:无缓存

如果旧浏览器不正确地兼容 HTTP 1.1,它们可能会忽略这一点。对于那些你可以尝试标题的人:

Pragma:无缓存

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


规范表明,未经重新验证,不得重复使用响应。 Cache-Control:no-store 是官方的方法,它表明响应甚至不首先存储在缓存中。
A
Anders Sandvig

将修改后的 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

设置很久以前的 Last-Modified 对缓存没有影响,除了由于启发式重新验证而让缓存的响应使用更长时间。
C
Community

PHP documentation for the header function 有一个相当完整的示例(由第三方提供):

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

这显然是错误的。第二次调用 header() 以获得过期、缓存控制和 Pragma 完全覆盖以前设置的值。
@porneL:不,不要覆盖以前设置的值,因为他将 false 作为第二个参数传递,告诉不要覆盖以前的值。
@JulienPalard 在我发表评论后,答案已被编辑。它仍然没有多大意义。
如果您想在 9 之前的 IE 中工作,请不要发送多个 Cache-Control 标头。永远不要发送预检查或后检查。 blogs.msdn.com/b/ieinternals/archive/2009/07/20/…
A
Albert

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


u
user2321638

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

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

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


我的 mozilla 19.x 浏览器问题也通过代码片段得到解决。自动完成=“关闭”。谢谢你。
C
Community

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


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

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


C
Community

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

<body onunload=""> 

这个 hack 显然破坏了 Safari 中的后向缓存:Is there a cross-browser onload event when clicking the back button?


酷,我已经测试过了,这实际上适用于 Safari (5.1.7) 但不适用于 Opera。
O
ObiHill

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

ExpiresDefault "access plus 0 seconds"

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

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

如果您的动态文件(例如 php 等)正在被浏览器缓存,而您无法弄清楚原因,这也可能会派上用场。检查ExpiresDefault


H
Harry

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


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

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

C
Community

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


我不知道使用这个配置的 Apache 会有什么行为: - Pragma/Cache-Control 具有相同的角色,你给他们 2 个不同的配置。有点奇怪。 - no-store 意味着资源不应该被缓存。那么如何重新验证呢?
u
user3253726

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

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

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

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

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

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

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

R
Racil Hilan

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

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

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

这不是已经在网站上多年的答案中多次提及了吗?
META 指令适用于 Internet Explorer 和 Edge 18 及更早版本。现代浏览器不支持它们。 crbug.com/2763
Y
YakovL

请参阅此链接到缓存案例研究:

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

总结,根据文章,只有 Cache-Control: no-store 适用于 Chrome、Firefox 和 IE。 IE 接受其他控件,但 Chrome 和 Firefox 不接受。该链接是一个很好的阅读完整的缓存和记录概念证明的历史。


e
elle0087

我已经以这种方式解决了。

2个考虑:

1)服务器端事件不会在点击后触发,而不是javascript。

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

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

然后在我的页面中我添加了这个:(这是在点击后触发的)

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

</script>

没有其他的。

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


C
CodeMind

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

 <location path="index.html">
    <system.webServer>
      <httpProtocol>
        <customHeaders>
          <add name="Cache-Control" value="no-cache" />
        </customHeaders>
      </httpProtocol>
    </system.webServer>
  </location>

A
Antonio Ooi

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

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

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