【问题标题】:"Cache-Control: max-age=0, no-cache" but browser bypasses server query (and hits cache)?“Cache-Control: max-age=0, no-cache”但浏览器绕过服务器查询(并命中缓存)?
【发布时间】:2015-05-18 11:33:40
【问题描述】:

我正在使用 Chrome 40(非常漂亮和现代)。

Cache-Control: max-age=0, no-cache 已在所有页面上设置 - 因此我希望浏览器仅在首先与服务器检查并获得 304 Not Modified 响应时才使用其缓存中的某些内容。

但是,在按下后退按钮时,浏览器会愉快地访问自己的缓存,而不需要与服务器进行检查。

如果我在新选项卡中打开与返回按钮相同的页面,那么它会检查服务器(并在事情发生变化时收到303 See Other 响应)。

请参阅下面的屏幕截图,显示 Chrome 开发者工具的“网络”选项卡中两种不同情况的输出。

我想我可以使用max-age=0, no-cache 作为no-store 的更轻量级的替代品,我不希望用户通过后退按钮看到陈旧的数据(但数据是无价值的,因此可以缓存)。

我对@9​​87654330@(参见herehere SO)的理解是,浏览器必须始终重新验证所有响应。那么为什么 Chrome 在使用返回按钮时不这样做呢?

no-store 是唯一的选择吗?


200 按下返回按钮时的响应(来自缓存):

303 在新标签页中请求同一页面时的响应:

【问题讨论】:

    标签: google-chrome http-headers browser-cache


    【解决方案1】:

    来自http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1

    无缓存

    如果 no-cache 指令未指定字段名称,则缓存不得使用响应来满足后续请求,而无需与源服务器成功重新验证。这允许源服务器阻止缓存,即使缓存已配置为向客户端请求返回陈旧响应。

    如果 no-cache 指令确实指定了一个或多个字段名称,则缓存可以使用响应来满足后续请求,但受缓存的任何其他限制。但是,如果没有与源服务器成功重新验证,则不得在对后续请求的响应中发送指定的字段名。这允许源服务器防止在响应中重复使用某些标头字段,同时仍允许缓存响应的其余部分。

    除了名字所暗示的,no-cache 不要求响应不能存储在缓存中。它只指定缓存的响应在没有重新验证的情况下不得重用于后续请求,因此它是must-revalidate, max-age=0的简写。

    什么是后续请求取决于浏览器,而我的理解是使用后退按钮没有。这种行为因不同的浏览器引擎而异。

    no-store 禁止对所有请求使用缓存的响应,而不仅仅是后续请求。

    请注意,即使使用no-store,RFC 实际上也允许客户端存储响应以在历史缓冲区中使用。这意味着即使指定了no-store,客户端仍然可以使用缓存的响应。

    后一种行为涵盖页面已在浏览器历史记录中记录其原始页面标题的情况。另一个用例是各种移动浏览器的行为,它们不会丢弃前一个页面,直到下一个页面完全加载,因为用户可能想要中止。

    为了澄清后退按钮的行为:它不受任何缓存头的影响,根据http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.13

    用户代理通常具有历史机制,例如“返回”按钮和历史列表,可用于重新显示在会话中较早检索到的实体。

    历史机制和缓存是不同的。特别是历史机制不应该尝试显示资源当前状态的语义透明视图。相反,历史机制旨在准确显示用户在检索资源时所看到的内容。

    默认情况下,过期时间不适用于历史机制。如果实体仍在存储中,即使实体已过期,历史机制也应该显示它,除非用户已专门配置代理以刷新过期的历史文档。

    这意味着在使用后退按钮时不尊重任何缓存控制标头是推荐的行为。如果您的浏览器碰巧遵守了回溯的到期日期,或者将 no-store 指令不仅应用于浏览器缓存而且还应用于历史记录,那么它实际上已经偏离了该建议。

    如何解决:
    你不能,也不应该这样做。如果用户返回之前访问过的页面,大多数浏览器甚至会尝试恢复视口。如果这是用户离开页面之前的原始行为,您可以使用 AJAX 等延迟机制来刷新内容,否则您甚至不应该修改内容。

    【讨论】:

    • 这听起来像是一个合理的解释,但它是否基于任何来源?你说它是“由浏览器决定是否有资格作为后续请求”-但这是否在任何地方正式说明过?如果没有参考,这只是对 Chrome 行为的一个很好的事后证明。
    • @GeorgeHawkins w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.13 History mechanisms and caches are different. In particular history mechanisms SHOULD NOT try to show a semantically transparent view of the current state of a resource. Rather, a history mechanism is meant to show exactly what the user saw at the time when the resource was retrieved.
    • 这是否意味着每个修改资源的 AJAX 请求:例如PUTPATCH 必须始终伴随着 GET 请求重新获取资源?这样历史机制会在用户退出时恢复视图吗?这有点违背了缓存的目的,即减少请求。
    【解决方案2】:

    看起来这是 Chrome 中使用后退按钮的一个已知“怪癖”。此处的错误报告中对此问题进行了很好的讨论:

    https://code.google.com/p/chromium/issues/detail?id=28035

    遗憾的是,看起来大多数人都改用 no-store 了。

    我希望大多数用户已经习惯了使用后退按钮无法刷新整个页面的体验。如果您考虑大多数 Angular 或 Backbone 应用程序自己管理后退操作,以便您只刷新内容而不是页面。考虑到这一点,我怀疑让客户在他们回来时刷新或获取更新可能不会那么意外。

    【讨论】:

    • 我没有考虑过对 Angular 等的影响,这实际上是我所见过的当前行为的最佳理由。谢谢 :) 如果我们能找到来自 Google 的参考资料,表明当前行为是基于类似这样的有意识的决定,那就太好了。谷歌似乎并没有竭尽全力澄清他们对您提到的错误的回应(事实上我认为他们误解了它 - 他们已经将它与我感觉不相关的问题合并)。
    • 我希望我可以分红,但显然这是not allowed。您对 Angular 的错误链接和评论提供了丰富的信息,但 Ext3h 的回答更接近于指出为什么允许行为是这样的。
    【解决方案3】:

    您是否尝试过使用完整的旧无缓存标头集?

    <meta http-equiv="cache-control" content="max-age=0" />
    <meta http-equiv="cache-control" content="no-cache" />
    <meta http-equiv="expires" content="0" />
    <meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
    <meta http-equiv="pragma" content="no-cache" />
    

    这似乎一直有效,除非您运行的是“pushState”网络。

    【讨论】:

      猜你喜欢
      • 2019-07-09
      • 2015-04-08
      • 2018-11-24
      • 2015-10-19
      • 2018-10-06
      • 1970-01-01
      • 1970-01-01
      • 2022-11-17
      • 2015-02-14
      相关资源
      最近更新 更多