在动态加载的内容上使用缓存控制“必须重新验证”的正确方法是什么?

时间:2018-06-27 06:46:20

标签: html browser-cache

要给出背景,我有一个非常大的js文件,该文件会动态加载到脚本标签中。客户端会不时更改文件。如果没有更改,我们不希望重新加载。

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

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

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

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

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

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

似乎上述问题仅在动态加载的资源上发生。

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

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

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

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

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。

为什么会发生这种情况?

2 个答案:

答案 0 :(得分:0)

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

如果文件内容发生更改,只需根据新内容生成新文件名。 Webpack捆绑软件中经常使用此技术。无需再玩标题了!

答案 1 :(得分:0)

每次使用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指令,指示浏览器每次使用缓存文件之前都要向服务器检入。