如何防止返回304的请求

cor*_*ore 56 etag caching http http-headers

浏览器何时不向服务器请求文件?

换句话说,我有一个JavaScript文件正在服务.其HTTP响应报头具有一个ETag,Cache-Control: publicExpires: Tue, 19 Jan 2038 03:14:07 GMT.

304浏览器缓存已准备好后服务器返回a .

我的问题是,为什么浏览器甚至检查服务器并首先获得一个304?我不希望浏览器询问是否有新版本 - 它应该直接从浏览器缓存加载而不检查服务脚本的服务器的修改.

HTTP响应头的哪些组合实现了这一点?

Mar*_*ery 90

首先,相关的HTTP规范是RFC 7234.如果你看一下规范,你会发现两件事:

  • 在任何情况下,规范都不需要缓存提供内容的缓存版本而无需重新验证.有很多地方规范指出缓存不得使用缓存内容来满足请求,但根本没有任何地方它指示它必须这样做或者它必须不重新验证.因此,如果他们愿意,浏览器供应商总是可以自由地重新验证.
  • 其次,你最终没有做错任何事.浏览器可以自由缓存响应,并根据您返回的标头使用这些缓存的响应.关键点在第4节,其中注意到服务缓存响应的条件之一是响应是:

    • 新鲜的(见4.2节),或

    • 允许陈旧(见第4.2.4节),或

    • 成功验证(参见第4.3节).

    由于你正在吐出一个Expires远在未来的标题,并且未来还没有达到这一点,因此响应是"新鲜的",因此不需要重新验证.所以你正在做的事情,规范建议你应该在你的最后.(虽然使用Cache-Control: max-age=foo是一种比使用Expires:标头更现代的设置缓存到期时间的方法.)

因此,如果您想要更改浏览器的缓存行为,那么您就不走运了.

但是,事情可能没有你想象的那么糟糕.你可能只看到一个请求和304,因为你在测试时刷新了浏览器中的页面.浏览器根据触发请求的方式不同地处理缓存的资源.

我运行了一个简单的测试,其中我创建了一个HTML页面,其中包含<script>指向JS文件的<img>标记,指向图像的<link>标记以及指向CSS样式表的标记.所有这些文件都托管在配置为以下服务的Apache服务器上:

  • 一个E-Tag标题,
  • 最后修改日期,
  • 一个Cache-Control: max-age=172800

当然,所有资源都在首页加载时提供200个代码.此后,使用默认设置在Chrome或Firefox中进行测试,我观察到:

  • 如果您刷新通过页面F5键或刷新按钮,页面和所有的资源重新生效(即请求向服务器的每个资源和304返回).
  • 如果您通过链接返回页面或在新选项卡中输入URL到URL栏,则不会进行重新验证(即没有请求).
  • 在Chrome中,如果您通过选择URL栏并按Enter来刷新页面,则页面本身会重新生效,但没有其他资源可以.在Firefox中,页面和资源都不会重新验证.

此页面表明Internet Explorer具有相同的行为:

在许多情况下,Internet Explorer需要检查缓存条目是否有效:

  • 缓存条目没有到期日期,并且首次在浏览器会话中访问内容
  • 缓存条目具有到期日期但已过期
  • 用户通过单击"刷新"按钮或按F5请求页面更新

换句话说,如果用户明确刷新页面,通常只会看到这些重新验证请求.除非您对浏览器缓存的行为有一些非常特殊的要求,否则这种行为似乎非常合理.

谷歌Mozilla都有一些关于HTTP缓存的文档(我在MSDN或Apple Developers网站上找不到任何相同的东西),但都没有暗示是否存在任何特定于供应商的缓存头,可用于修改浏览器使用的规则选择何时重新验证.你想做什么根本不可能.

如果您确实需要更多地控制此行为,您可以查看HTML5应用程序缓存或使用HTML5本地存储滚动您自己的缓存逻辑,就像basket.js一样.

  • 这是一个非常好的答案.现在,您还可以提及ServiceWorker作为更好地控制缓存资源的选项. (2认同)