"Cache-Control: max-age=0, no-cache" 但浏览器绕过服务器查询(并命中缓存)?

"Cache-Control: max-age=0, no-cache" but browser bypasses server query (and hits cache)?

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

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

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

如果我打开同一个页面,当我使用后退按钮到达时,在一个新选项卡中,它会检查服务器(并在事情发生变化时得到 303 See Other 响应)。

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

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

我对 no-cache 的理解(请参阅 SO 上的 here and here)是浏览器必须始终重新验证所有响应。那么,为什么 Chrome 在使用后退按钮时不执行此操作?

no-store是唯一的选择吗?


200 按下后退按钮时的响应(来自缓存):

303 在新选项卡中请求同一页面时的响应:

看起来这是 Chrome 中已知的 'quirk',使用后退按钮。此处的错误报告中对该问题进行了很好的讨论:

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

遗憾的是,大多数人似乎又转而使用无商店。

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

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

no-cache

If the no-cache directive does not specify a field-name, then a cache MUST NOT use the response to satisfy a subsequent request without successful revalidation with the origin server. This allows an origin server to prevent caching even by caches that have been configured to return stale responses to client requests.

If the no-cache directive does specify one or more field-names, then a cache MAY use the response to satisfy a subsequent request, subject to any other restrictions on caching. However, the specified field-name(s) MUST NOT be sent in the response to a subsequent request without successful revalidation with the origin server. This allows an origin server to prevent the re-use of certain header fields in a response, while still allowing caching of the rest of the response.

除了顾名思义,no-cache 不要求响应不得存储在缓存中。它仅指定缓存的响应不得重复用于服务 没有 re-validating 的后续 请求,因此它是 must-revalidate, max-age=0 的 shorthand。

由浏览器决定什么是 后续 请求,据我所知,使用 back-button 则不然。此行为因不同的浏览器引擎而异。

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

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

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

澄清后退按钮的行为:根据 http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.13

,它不受任何缓存 header 的影响

User agents often have history mechanisms, such as "Back" buttons and history lists, which can be used to redisplay an entity retrieved earlier in a session.

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.

By default, an expiration time does not apply to history mechanisms. If the entity is still in storage, a history mechanism SHOULD display it even if the entity has expired, unless the user has specifically configured the agent to refresh expired history documents.

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

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

您是否尝试过使用完整的旧集 no-cache headers?

<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" 网络。