如何阻止 Opera 缓存页面?

Posted

技术标签:

【中文标题】如何阻止 Opera 缓存页面?【英文标题】:How do I stop Opera from caching a page? 【发布时间】:2010-05-19 15:16:47 【问题描述】:

我试图让 Opera 每次都重新请求一个页面,而不是仅仅从缓存中提供它。我正在发送 'Cache-control: no-cache' 和 'Pragma: no-cache' 响应标头,但似乎 Opera 只是忽略了这些标头。它在其他浏览器中运行良好 - Chrome、IE、Firefox。

我想要做的是让 Opera 在用户单击浏览器上的“后退”按钮时重新请求页面。

【问题讨论】:

【参考方案1】:

作为用户,我绝对讨厌在我使用后退按钮时通过强制重新加载来减慢历史导航速度的页面。 (如果您每天使用的浏览器注意各种缓存指令,并让它们以您想要的方式影响历史导航,作为开发人员,您可能会注意到一些网站的速度变慢...)

如果您有一个非常强大的用例来执行此操作,我会说您的架构在某种意义上可能是“错误的” - 例如,如果您在不断更新数据的不同“视图”之间切换,因此想要当用户返回时强制重新加载也许使用 Ajaxy 技术将不断变化的数据加载到当前页面会更好?

Opera 的实现是有目的的——“缓存”在概念上与“历史导航”不同,前者更多的是在磁盘上和会话之间存储东西,后者是切换回您刚刚访问的临时隐藏页面,在你离开它的状态。

但是,如果您真的非常需要它,则此政策中存在一个漏洞,可以实现您想要的行为。发送“Cache-control: must-revalidate”将强制 Opera 重新加载导航中的每个页面,但如果您通过 https 发送页面。 (这是偏执的银行要求并打算为该功能提供的功能,如果应用在 http 上,它会减慢太多正常网站的速度。

【讨论】:

“这是一个由偏执的银行要求并打算用于的功能,如果在 http 上应用它会减慢太多正常网站的速度”你是说浏览器不应该真正用于可能有敏感的应用程序数据? :-) 如果数据真的很敏感,网站应该使用 https。 :-) 这里的网络规范有一个漏洞,因为服务器和浏览器之间没有共享“会话”的概念。如果服务器可以告诉浏览器“用户刚刚注销/超时并且我们关闭了她的会话,请禁止使用后退按钮查看会话开始以来的历史记录”,我们将能够在可用性和安全性之间找到更好的平衡. 我同意这两点:(i) Web 规范中存在关于“共享会话状态”的漏洞和 (ii) https 应该用于真正敏感的情况。但是,“真正敏感的数据”表明数据安全不是数字的,而是模拟的措施。其他浏览器通过不允许缓存和必须重新验证来支持这一点,这允许进一步管理安全/隐私。 Opera 不支持这一点——对与错,我不关心。我需要一个解决方案来解决这种不一致。你在 Opera 工作,你有什么建议? (即脚本、标题等)Thks 如果您不在 https 上,我无法可靠地强制重新验证。我们正在制定解决此问题的提案,例如:ietf.org/id/draft-pettersen-cache-context-05.txt 实际实施可能还需要一段时间 - 等待对该提案的进一步讨论。 对我来说,这不适用于最新的 Opera。不得不按CTRL+F5,我每周只重新生成一次html,但它必须显示最新的内容。 【参考方案2】:

听起来您的问题与this answer 有关。在测试了您的标头和建议的标头后,我只能在 Internet Explorer 中重现您的预期行为。

【讨论】:

我在 Opera 上反复重现此问题。它似乎是唯一不一致的浏览器。我已经阅读了他们处理缓存的严格、有原则的方法。但这实际上只是看起来像一个安全漏洞,没有做额外的工作。我真的很想要一个明确的解决方案,它也可以用来解决 nishkarr 的问题。头缓存控制响应头在opera中不像在其他浏览器中那样工作。解决方法是什么?【参考方案3】:

简单的服务器缓存控制,无需标头或前端脚本

零依赖,通用语言版


您可以通过将 md5 或 sha1 校验和附加到文件名来强制全局重新缓存而不使用标头。

如果完全匹配,它将缓存,否则将其视为新资源。

适用于所有浏览器 验证为严格的 HTML5 (最初没有,但已更新。未经 XHTML 测试,但可能对此无效) 不需要额外的标题 保持前端关注点和后端关注点很好地分离。 不需要客户端完整性检查或源验证。 任何可以打印 html 的东西都可以做到这一点,包括静态内容 如果不是静态的,则可以轻松地将运行时控制扩展到最终用户(如果需要,通过身份验证),这允许简单的页面标志来确定返回的缩小、美化或调试源。 将客户端缓存控制完全封装在内容服务机制中,维护起来超级简单。

作为一项额外福利,通过延迟浏览器缓存的校验和自动引入 版本化客户端缓存,如果您有备用版本并且需要对发布包以确定它的最低稳定依赖版本或其他东西。

您不必永远摆弄您的浏览器以使缓存不再干扰您的开发过程。

这种方法也可用于版本化的图像、视频、音频、pdf 等。几乎所有用作静态数据的资源都将类似地操作,在第一次请求内容时缓存,并自动持久化如果文件没有更改,则无需进一步考虑。


这是 RFC 有效标记。注意脚本和链接标签有一个获取字符串:

?checksum=ba411cafee2f0f702572369da0b765e2

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">

  <title>Client Cache Control Example</title>
  <meta name="description" content="You're only going to cache this when the content changes, and always when the content changes.">
  <meta name="author" content="https://***.com/users/1288121/mopsyd">

  <!-- Example Stylesheet -->
  <link rel="stylesheet" href="css/styles.css?checksum=ba411cafee2f0f702572369da0b765e2">

  <!-- Example Script -->
  <script src="js/scripts.js?checksum=ba411cafee2f0f702572369da0b765e2"></script>
</head>
<body>
</body>
</html>

GET 字符串?checksum=ba411cafee2f0f702572369da0b765e2 指的是资源文件大小的MD5 或SHA1 哈希。它可以通过命令行、语言结构或从Content-Length: 标头的值散列来获得。然后,通过将其作为 GET 字符串附加到文件名来构造 hrefsrc 属性。

此浏览器会将它们解释为不同的,并单独缓存。

如果是静态资源,服务器将忽略 GET 参数,但如果是动态服务,则 GET 参数将可用于解释语言。

这意味着每当链接中的哈希值发生变化时,浏览器都会独立地缓存该特定版本一次,然后一直保存到永远,或者Expires: 过去,以较早者为准。

由于校验和是文件大小的直接反映,您可以将Expires: 设置为永远,这并没有太大区别。只要该文件更改了一个字节,您仍然会立即看到您的更改。

使用您通常使用的任何实用程序生成您的 css 或 js 源代码。

如果您是动态服务,在运行时对文件大小运行 md5 或 sha1 校验和,如果您要生成静态内容,则在 编译时(例如 ApiGen 文档)

提供带有哈希作为 GET 字符串附加到文件名的普通文件(例如:styles.css 变为 styles.css?checksum=ba411cafee2f0f702572369da0b765e2

文件中的任何更改都会强制重新缓存,这意味着您会立即看到反映的真实值。

可选,但非常好:这种方法的另一个好处是您可以轻松设置一个 dev GET 标志,这将使所有前端源使用您自己的任何自定义解析为美化的开发源启用调试功能,或使用它来解释版本控制标志。您可以进行冗余检查以确保该标志仅由服务器从已知的开发 IP 地址、代理身份验证等传递,否则如果您需要它安全,则不会兑现。我通常会尽可能地划分我的前端源代码,类似于:

这就是它现在在现场做的事情(缩小生产、缓存、默认、?checksum=ba411cafee2f0f702572369da0b765e2)。 这就是它现在应该在现场做的,美化到足以让我阅读(美化制作,never cached,?debug_pretty_source=true)。 这就是我用来弄清楚如果它存在于前两者中的情况下没有做什么它应该在现场做的事情(启用调试,never cached,ACL/白名单授权,?debug_dev_enable=true 或类似的)。

您可以通过使用版本号而不是校验和将相同的原则应用于软件包版本,前提是您的版本不会更改。校验和的可读性较差,但更易于自动化并与确切的更改保持同步,但版本后缀也可用于测试包的稳定性,前提是版本号反映了不可变的资源。

【讨论】:

应该注意的是,http 传输代理有时会使用GET 干扰这一点,这取决于对您服务器的请求的特定网络路径。在这种情况下,可以通过将哈希直接附加到文件名而不是使用获取字符串来规避这种情况,然后使用.htaccess 重写规则将它们剥离,即使在代理干扰的情况下也可以。这通常不是问题,但有时可能会出现在某些极端情况下。例如:styles.ba411cafee2f0f702572369da0b765e2.css 而不是 styles.css?checksum=ba411cafee2f0f702572369da0b765e2【参考方案4】:

在寻找解决方案时发现了这个。不高兴,所以写了一些javascript来解决可能对其他人有用的问题。

&lt;HEAD&gt; 上面的任何其他javascript:

<script>
    if( typeof(opera) != 'undefined' )  // only do for Opera
       if (window.name == 'previously_loaded')  // will be "" before page is loaded
            alert('Reloading Page from Server'); // for testing
            window.name = ''; // prevent multiple reload
            window.location.reload(true);
       
    
</script>

现在更改窗口名称,以便 Opera 在随后从缓存加载时检测到它:

window.name = 'previously_loaded';

在“窗口加载”期间不会执行的 js 块中插入这一行,从而导致无限重新加载。对我来说,除非有人通过链接退出,否则无需刷新页面,所以我只是将其添加到我的 onclick/onunload 函数中。

Before and after demos 这里还有一些注释。我打算将它添加到我的博客中。我只有几个较晚版本的 Opera,所以我会很感激在我得到鸡蛋之前尝试一些演示。

编辑:刚刚意识到,如果稍后访问的站点更改了窗口名称(其持久性),则不会发生后退选项卡重新加载。只需将上面的 if 语句更改为:

 if (window.name != "") 

在多个选项卡中打开演示时效果很好;但我隐约记得窗口名称应该是唯一的;所以我修改了演示以生成一个唯一的名称。

window.name = new Date().getTime();

【讨论】:

以上是关于如何阻止 Opera 缓存页面?的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC 阻止当前请求的视图页面缓存OutputCache

如何阻止 chrome 缓存

JSP页面弹出问题

Rail片段缓存如何使您的应用受益,即阻止数据库调用?

怎么阻止vue的数据更新刷新事件

您将如何阻止页面自动刷新?