要给出背景,我有一个非常大的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。
为什么会发生这种情况?
答案 0 :(得分:0)
重命名JS文件,以便该名称包含其中的文件内容哈希,例如:your_module.489d43f35d9b718c5cdc4f0828a7c6c7.js
并将文件标记为immutable。这样,客户端将只下载一次文件。
如果文件内容发生更改,只需根据新内容生成新文件名。 Webpack捆绑软件中经常使用此技术。无需再玩标题了!
答案 1 :(得分:0)
每次使用max-age=0
停用任何类型的缓存时,它都会重新加载文件。
浏览器可以通过两种方式确认其在缓存中的文件是否陈旧:
两者都要求浏览器具有缓存中的文件,否则,这两种方法都无法使用。为了使浏览器将文件保留在缓存中,必须允许它在缓存中保留一段时间。通过指定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
指令,指示浏览器每次使用缓存文件之前都要向服务器检入。