我注意到一些浏览器(特别是Firefox和Opera)非常热衷于使用.css和.js文件的缓存副本,甚至在浏览器会话之间。当您更新其中一个文件时,这会导致一个问题,但用户的浏览器会继续使用缓存的副本。

当文件发生更改时,强迫用户浏览器重新加载文件的最优雅的方法是什么?

理想情况下,该解决方案不会强制浏览器在每次访问页面时重新加载文件。


我发现John Millikin和da5id的建议很有用。这有一个专门的术语:自动版本控制。

我在下面发布了一个新的答案,这是我最初的解决方案和约翰的建议的结合。

SCdF建议的另一个想法是将伪查询字符串附加到文件中。(一些自动使用时间戳作为伪查询字符串的Python代码是由pi..提交的)

然而,关于浏览器是否缓存带有查询字符串的文件还存在一些讨论。(请记住,我们希望浏览器缓存该文件并在以后的访问中使用它。我们只希望它在文件更改时再次获取该文件。)


当前回答

我将文件内容的MD5哈希值放在其URL中。这样我就可以设置一个很长的过期日期,而不必担心用户使用旧的JS或CSS。

我还在运行时(或在文件系统更改时)对每个文件进行一次计算,因此在设计时或构建过程中没有什么有趣的事情要做。

如果你使用ASP。NET MVC,那么你可以在我的另一个答案中查看代码。

其他回答

这是一个纯JavaScript解决方案

(function(){

    // Match this timestamp with the release of your code
    var lastVersioning = Date.UTC(2014, 11, 20, 2, 15, 10);
 
    var lastCacheDateTime = localStorage.getItem('lastCacheDatetime');

    if(lastCacheDateTime){
        if(lastVersioning > lastCacheDateTime){
            var reload = true;
        }
    }

    localStorage.setItem('lastCacheDatetime', Date.now());

    if(reload){
        location.reload(true);
    }

})();

上面将查找用户最后一次访问您的站点的时间。如果最后一次访问是在发布新代码之前,它使用location.reload(true)强制从服务器刷新页面。

我通常把这作为<head>中的第一个脚本,因此它在任何其他内容加载之前进行评估。如果需要重新加载,用户很难注意到。

我使用本地存储来存储浏览器上最后一次访问的时间戳,但是如果您希望支持旧版本的IE,您可以添加cookie。

对于开发:使用浏览器设置:例如,Chrome网络选项卡有一个禁用缓存选项。

对于生产:使用服务器端呈现框架或纯JavaScript代码将唯一的查询参数附加到请求(例如,q?Date.now())。

// Pure JavaScript unique query parameter generation
//
//=== myfile.js

function hello() { console.log('hello') };

//=== end of file

<script type="text/javascript">
    document.write('<script type="text/javascript" src="myfile.js?q=' + Date.now() + '">
    // document.write is considered bad practice!
    // We can't use hello() yet
</script>')

<script type="text/javascript">
    hello();
</script>

这里的所有答案似乎都表明在命名方案中存在某种版本控制,但这也有其缺点。

浏览器应该通过读取web服务器的响应,特别是HTTP报头来清楚地知道什么该缓存,什么不该缓存——这个资源的有效期是多长?自上次检索该资源以来,该资源是否已更新?等。

如果事情配置“正确”,只是更新你的应用程序的文件应该(在某些时候)刷新浏览器的缓存。例如,你可以配置你的web服务器,告诉浏览器永远不缓存文件(这是一个坏主意)。

更深入的解释在Web缓存的工作原理中。

我这样做的方法是简单地有链接元素到服务器端包含:

<!--#include virtual="/includes/css-element.txt"-->

css-element.txt的内容在哪里

<link rel="stylesheet" href="mycss.css"/>

如果你想链接到my-new-css。css,你只需要改变include。

RewriteRule需要对JavaScript或CSS文件进行一个小的更新,这些文件最后包含点符号版本控制。例如,json-1.3.js。

我添加了一个点否定类[^。]转换为正则表达式,即.number。将被忽略。

RewriteRule ^(.*)\.[^.][\d]+\.(css|js)$ $1.$2 [L]