我正在使用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
(请参阅here和here SO)的理解是,浏览器必须始终重新验证所有响应。那么为什么Chrome在使用后退按钮时不这样做呢?
no-store
是唯一的选择吗?
200
响应(来自缓存):
303
在新标签页中请求同一页面的响应:
答案 0 :(得分:23)
来自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
,它不受任何缓存标题的限制用户代理通常具有历史机制,例如" Back"按钮和历史列表,可用于重新显示先前在会话中检索的实体。
历史机制和缓存是不同的。特别是历史机制不应该试图显示资源当前状态的语义透明视图。相反,历史机制旨在准确显示用户在检索资源时看到的内容。
默认情况下,到期时间不适用于历史记录机制。如果实体仍在存储中,即使实体已过期,历史机制也应该显示它,除非用户已经专门配置代理来刷新过期的历史文档。
这意味着在使用后退按钮时不尊重任何缓存控制标头是建议的行为。如果您的浏览器恰好遵守过期的过期日期或将no-store
指令不仅应用于浏览器缓存而且应用于历史记录,那么它实际上已经偏离了该建议。
如何解决:
你不能,你不应该这样做。如果用户返回之前访问过的页面,大多数浏览器甚至会尝试恢复视口。如果这是用户离开页面之前的原始行为,您可以使用像AJAX这样的延迟机制来刷新内容,否则您甚至不应该修改内容。
答案 1 :(得分:1)
看起来这是一个众所周知的“怪癖”。在Chrome中使用后退按钮。这里的错误报告中有一个很好的讨论问题:
https://code.google.com/p/chromium/issues/detail?id=28035
可悲的是,看起来大多数人都会改为使用无商店。
我希望尽管大多数用户都习惯使用后退按钮获得整页刷新的体验。如果您考虑大多数Angular或Backbone应用程序自己管理后退操作,以便您只刷新内容而不是页面。考虑到这一点,我怀疑让客户刷新或在他们回来时获得更新可能不会出乎意料。
答案 2 :(得分:1)
您是否尝试使用完整的旧缓存标头集?
<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" />
这似乎一直有效,除非你正在运行&#34; pushState&#34;幅。