为什么仅使用ETag无法使浏览器缓存失效?

17

我已经阅读了许多相关文章,还有这里介绍的非常好的关于HTTP缓存的文章:https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=en#invalidating-and-updating-cached-responses但是对我来说仍然不清楚:

为什么发送ETag头不能足以使浏览器缓存失效?为什么每个人都建议实际更改资源的URL /文件名以强制浏览器重新下载文件?如果浏览器已经使用特定的ETag缓存了文件,并且在服务器上修改了ETag,那么这是否足够?

1个回答

21

我发现以下页面很有帮助:

这行来自MDN的ETag页面,分享了关键点(已加重强调):
如果用户再次访问已设置ETag的给定URL,并且它已经过期而不可用,客户端将在If-None-Match标头字段中发送其ETag的值...
客户端将使用ETag在资源变得“陈旧”后重新验证资源。但是什么构成“陈旧”?
这就是Cache-Control标头派上用场的地方。可以通过响应发送Cache-Control标头以告知客户端可以缓存项目的时间,直到应将其视为过时。例如,Cache-Control:no-cache表示应立即将资源视为过时。有关可用Cache-Control值的更多信息,请参见MDN Cache-Control页面
当浏览器尝试处理被视为过时的缓存资源的请求时,它将首先使用资源的最后一个ETag值通过If-None-Match请求标头向服务器发送重新验证请求,如MDN的ETag页面所述。它还可以使用Last-Modified响应标头作为If-Modified-Since请求标头的辅助选项。

如果服务器确定客户端的ETag值(在If-None-Match请求头中)是当前的,则它将用一个304(未修改)HTTP状态代码和一个空的正文来响应,表示客户端可以使用缓存条目。否则,服务器将用一个200 HTTP状态代码和新的响应正文来响应。

其他资源:

直接回答您的问题:

  • 为什么只发送 ETag 标头不足以使特定资源的浏览器缓存失效? -- 因为 ETag 标头在缓存条目被视为过期(例如通过在 Cache-Control 响应标头中设置的到期日期)之前不会得到验证。
  • 为什么每个人都建议实际更改资源的 URL/文件名以强制浏览器重新下载文件? -- 更改 URL/文件名或添加查询字符串将强制客户端避免使用缓存。这很简单,几乎可以保证缓存破坏。这并不意味着必须这样做,但在不一致的浏览器行为领域中,它往往是安全的。
  • 如果浏览器已经使用特定 ETag 缓存了文件,并且服务器上修改了 ETag,那么这是否足够? -- 从技术上讲,只要包括适当的 Cache-Control 标头(包括 PragmaExpires 标头),就应该足够。有关更多详细信息,请参见 如何控制所有浏览器上的网页缓存?

谢谢你提供详细答案。虽然从技术角度来看,如果所有浏览器、服务器和代理程序都在它们的实现上保持一致,我仍然认为仅使用ETag就足以满足所有缓存目的,但我已将其标记为接受。因此,除非我错了,否则我的问题的简单答案就是由于不同实现之间的不一致性问题。 - AsGoodAsItGets
对我来说,“陈旧”的概念是不必要的。浏览器可以保留文件的缓存版本,直到分配的缓存空间用尽并需要为更新的文件释放一些空间,或者特定文件的 ETag 在服务器上发生变化。我不明白为什么我们需要引入“陈旧”的概念。 - AsGoodAsItGets
2
很抱歉,我的回答可能没有清楚地解释什么是“过期”的资源。只有当资源“过期”时,客户端才会对缓存的资源的ETag(或Last-Modified日期)与服务器进行验证。因此,即使服务器的资源发生了更改,客户端也不会在满足这个“过期”要求之前实际检查这个更改。它将继续使用本地缓存,并且不会向服务器发送任何请求。从这个意义上讲,“过期”的概念非常重要,因为它决定了缓存资源的最大“过时”程度。 - Mike Hill
1
啊,这确实更有意义,可以为浏览器节省一些不必要的HTTP请求。再次感谢你的解释! - AsGoodAsItGets

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接