【问题标题】:what is the correct way to use cache control "must-revalidate" on dynamically loaded content?在动态加载的内容上使用缓存控制“必须重新验证”的正确方法是什么?
【发布时间】:2018-06-27 06:46:20
【问题描述】:

为了提供背景,我有一个非常大的 js 文件,它是在脚本标签中动态加载的。该文件由客户端不时更改。如果没有更改,我们不希望重新加载。

所以,我浏览了许多关于必须重新验证的 stackoverflow 文章。 基于此,我将缓存头实现为如下所示

Cache-Control: must-revalidate,max-age=0

我也启用了 ETag。 根据我的阅读和理解,这应该检查更改并仅在有任何更改时才加载

问题是在 Firefox 和 Chrome 中,无论是否有更改,都会下载文件。即即使文件和 Etag 未更改,浏览器也不会从缓存中加载。

在这种情况下发生了什么? 我在这里做错了吗? 我应该在使用 must-revalidate 时设置 long maxage,而不是将 maxage 设置为零?

我正在编辑这个问题,因为我在进一步检查时发现了一些重要的东西。请在发布答案之前阅读以下内容。

上面描述的这个问题似乎只发生在动态加载的资源上。

例如: 如果我在页面源中有一个脚本标签

<script src="some-js.js" type="text/javascript">

这尊重了必须重新验证的缓存标头。除非有更改,否则不会重新加载。

但是,如果脚本标签是动态加载的(粘贴我的代码以加载下面的动态脚本标签)

var s = document.createElement('script');
s.setAttribute('src', 'newjs.js');
s.setAttribute('id', 'script1');
s.type = 'text/javascript';
s.async = false;
s.onerror = errorcallback;
s.onload = loadcallback;
document.body.appendChild(s);

无论缓存头如何,这个 js 总是重新加载。

任何想法为什么会发生这种情况?

【问题讨论】:

    标签: html browser-cache


    【解决方案1】:

    它每次都重新加载文件,因为您使用max-age=0 停用任何类型的缓存。

    浏览器可以通过两种方式确认缓存中的文件是否过时:

    • ETags
    • 修改次数

    两者都要求浏览器拥有缓存中的文件,否则无论哪种方式都无法使用。为了让浏览器将文件保存在缓存中,必须允许它在缓存中保存一段时间。这是通过指定 max-age 和/或 Expires 标头来完成的。如果那是0,那么浏览器将不会缓存任何内容。所以,首先要让浏览器通过设置一个正的过期时间来缓存文件。

    接下来,must-revalidate 指定浏览器必须与服务器检查是否有更新的文件可用。如果有,服务器将发送较新的文件,否则服务器将响应一个 HTTP 状态代码,指示浏览器仍然具有最新版本,并且将省略发送冗长的响应正文。为此,必须有一种机制,浏览器和服务器可以使用它来确认文件的内容。这就是 ETag 或修改时间的用武之地。

    如果您的服务器为文件设置了 ETag 标头,该标头通常包含文件内容的哈希,则浏览器可以通过使用 If-None-Match 标头请求它来验证它。如果文件的 ETag 仍然匹配,服务器将返回 304 Not Modified
    另一种选择是让服务器设置一个Last-Modified 标头,它允许浏览器使用If-Modified-Since 请求文件,如果文件仍然是最新的,服务器再次以304 Not Modified 响应。

    如果没有must-revalidate,浏览器将简单地使用文件的缓存版本而不联系服务器,直到文件的max-age/Expires时间到达,然后它可能会再次使用If-None-Match请求文件/If-Modified-Since。使用must-revalidate 指令,每次使用缓存文件之前,都会指示浏览器与服务器签入。

    【讨论】:

    • 我不认为这是 max-age 的问题。在问题中查看我的新编辑(我在您发布此内容后添加)。如果是 max-age 的问题,其他具有相同缓存头的资源也会重新加载,但这个问题只发生在动态加载的资源中。
    【解决方案2】:

    重命名 JS 文件,使其名称中包含文件的内容哈希,例如:your_module.489d43f35d9b718c5cdc4f0828a7c6c7.js 并将文件标记为immutable。这样客户端只会下载一次文件。

    如果文件内容发生变化,只需根据新内容生成新的文件名即可。这种技术经常用在Webpack bundler 中。不再需要玩标题了!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-31
      • 2017-11-20
      • 2017-01-05
      • 2019-01-14
      • 2013-05-24
      • 1970-01-01
      • 2013-01-08
      • 2012-04-17
      相关资源
      最近更新 更多