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

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

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


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

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

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

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


当前回答

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

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

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

其他回答

我建议执行以下流程:

无论何时部署你的CSS和JavaScript文件。类似于:screen.1233.css(如果您使用版本控制系统,该数字可以是您的SVN版本) 缩小它们以优化加载时间

不要使用foo.css?version=1!

浏览器不应该缓存带有GET变量的url。据http://www.thinkvitamin.com/features/webapps/serving-javascript-fast网站报道,尽管ie和Firefox会忽略这一点,但Opera和Safari不会!相反,使用foo.v1234.css,并使用重写规则去除版本号。

静态文件的简单解决方案(仅用于开发目的),使用脚本标记注入将随机版本号添加到脚本URI

<script>
    var script = document.createElement('script');
    script.src = "js/app.js?v=" + Math.random();
    document.getElementsByTagName('head')[0].appendChild(script);
</script>

我没有发现客户端DOM方法动态创建脚本节点(或CSS)元素:

<script>
    var node = document.createElement("script");
    node.type = "text/javascript";
    node.src = 'test.js?' + Math.floor(Math.random()*999999999);
    document.getElementsByTagName("head")[0].appendChild(node);
</script>

假设你有一个文件可用:

/styles/screen.css

你可以在URI上附加一个包含版本信息的查询参数,例如:

/styles/screen.css?v=1234

或者你可以在前面加上版本信息,例如:

/v/1234/styles/screen.css

恕我直言,第二种方法更适合CSS文件,因为它们可以使用相对url引用图像,这意味着如果你指定一个背景图像,像这样:

body {
    background-image: url('images/happy.gif');
}

它的URL实际上是:

/v/1234/styles/images/happy.gif

这意味着如果您更新了使用的版本号,服务器将将其视为新资源,而不是使用缓存的版本。如果您的版本号基于Subversion、CVS等版本,这意味着CSS文件中引用的图像的更改将被注意到。第一种方案并不能保证这一点,即URL images/happy.gif相对于/styles/screen.css?V =1235是/styles/images/happy.gif,它不包含任何版本信息。

I have implemented a caching solution using this technique with Java servlets and simply handle requests to /v/* with a servlet that delegates to the underlying resource (i.e. /styles/screen.css). In development mode I set caching headers that tell the client to always check the freshness of the resource with the server (this typically results in a 304 if you delegate to Tomcat's DefaultServlet and the .css, .js, etc. file hasn't changed) while in deployment mode I set headers that say "cache forever".