javascript - 有什么简洁的方法来强制浏览器重新加载缓存CSS / JS文件么?

  显示原文与译文双语对照的内容

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

问题是:当用户改变文件时,强制浏览器重新加载文件的最优雅的方式是什么?

理想情况下,解决方案不会强迫浏览器在每次访问页面时重新加载文件。 我将发布我自己的解决方案作为答案,但我很好奇是否有人有更好的解决方案,我将让你的投票决定。

更新: 允许,这里不讨论一会儿之后,我发现约翰 Millikinda5id 建议的,以是有用的。 这里有一个术语: auto-versioning 。我在下面发布了一个新的答案,它是我最初的解决方案和john的建议。

另一种说法哪些建议是由 SCdF 将是把一个假查询字符串追加到该文件。 具有一个引导 string, ( 某些 python 代码以自动使用使用时间戳作为一个伪造的查询字符串是提交的性能指标 。) 然而,有一些问题比如写入到不论是否该浏览器会缓存一个文件 ( 记住,我们希望浏览器缓存文件并在以后的访问中使用它) 。 我们只希望它在更改时再次获取文件。因为不清楚用一个伪造的查询字符串发生了什么,所以我不接受这个答案。

时间:

约翰 Millikinda5id, 更新: 重写以合并 suggestions. 这个解决方案是用PHP编写的,但是应该很容易适应其他语言。

使用的文件,例如更新 2: 来融合评论,评论尼克约翰逊使原 .htaccess 正规表达式 可能会造成问题。 解决方案是只在末尾有 10位数字时重写。 ( 因为 10位数字涵盖了 9/9/2001 到 11/20/2286.的所有时间戳)

首先,我们使用下面的重写规则。htaccess:


RewriteEngine on
RewriteRule ^(.*).[d]{10}.(css|js)$ $1.$2 [L]

现在,我们编写以下PHP函数:


/**
 * Given a file, i.e./css/base.css, replaces it with a string containing the
 * file's mtime, i.e./css/base.1221534296.css.
 * 
 * @param $file The file to be loaded. Must be an absolute path (i.e.
 * starting with slash).
 */
function auto_version($file)
{
 if(strpos($file, '/')!== 0 ||!file_exists($_SERVER['DOCUMENT_ROOT']. $file))
 return $file;

 $mtime = filemtime($_SERVER['DOCUMENT_ROOT']. $file);
 return preg_replace('{.([^./]+)$}',".$mtime.$1", $file);
}

现在,无论你在哪里包含你的CSS,都要从以下位置进行更改:


<link rel="stylesheet" href="/css/base.css" type="text/css"/>

对此:


<link rel="stylesheet" href="<?php echo auto_version('/css/base.css');?>" type="text/css"/>

这样,你就再也不用修改链接标签,用户总是可以看到最新的CSS 。 浏览器可以缓存CSS文件,但是当你对CSS进行任何更改时,浏览器会将它视为一个新的URL,所以它不会使用缓存的副本。

这也可以使用图像,图标图标和 JavaScript 。 基本上不是动态生成的任何东西。

mod_pagespeed 插件插件的将为你做 auto-versioning 。 真是 slick 。

它从web服务器( 使用 PHP,Rails,python,静态 HTML -- ) 中解析HTML并重写指向 CSS,JS,图像文件的链接,这样它们就包含了一个标识代码。 它为修改过的url提供了一个非常长的缓存控制。 当文件改变时,它会自动改变 url,这样浏览器就必须为它们 re-fetch 。 它基本上只是工作,没有对代码的任何改动。 它甚至会在你出去的时候缩小你的代码。

简单Client-side技术

通常,缓存是好的。 因此,有一些技术,取决于你是否在开发网站时自己解决问题,或者是否在生产环境中控制缓存。

你网站的一般访问者与你在开发网站时没有相同的体验。 在缓存中,这样可能会将被enough,因为访问者平均来到这个网站 LESS 经常( 也许每个月只有几次,除非你是谷歌或者hi5网络),则会被 LESS 愿意让文件,有 如果你想在浏览器中强制一个新的版本,你总是可以向请求添加一个查询字符串,并在你进行主要更改时增加版本号:


<script src="/myJavascript.js?version=4"></script>

这将确保每个人都得到新文件。 它之所以工作是因为浏览器查看文件的URL,以确定它是否有缓存。 如果你的服务器没有设置为对查询字符串执行任何操作,它将被忽略,但是名称将看起来像一个新文件到浏览器。

另一方面,如果你正在开发一个网站,你不想每次保存对开发版本的更改时更改版本号。 那是很乏味的。

因此,在开发站点时,最好是自动生成查询字符串参数:


<!-- Development version: -->
<script>document.write('<script src="/myJavascript.js?dev=' + Math.floor(Math.random() * 100) + '"></script>');</script>

向请求中添加查询字符串是对资源的一个好方法,但是对于一个简单的网站,这可能是不必要的。 记住缓存是一件好事。

值得注意的是,浏览器不必吝啬地把文件保存在缓存中。 浏览器有针对这种事情的策略,它们通常由在HTTP规范中制定的规则播放。 当浏览器向服务器发出请求时,部分响应是过期标头。 通知浏览器应该保留多长时间的日期。 下次当浏览器遇到同一个文件的请求时,它会看到它在缓存中有一个副本,并查看过期日期以决定是否使用它。

所以不管你相信与否,实际上是你的服务器让浏览器缓存变得持久。 你可以调整你的服务器设置并更改EXPIRES头,但我上面编写的小技巧可能是你更简单的方法。 因为缓存是良好的,你通常要设置该日期远到未来( 一个"的far-future过期标头"),然后使用上面所介绍的技术来强制进行更改。

如果你对更多关于HTTP的信息感兴趣,或者这些请求是如何制作的,那么一本好书就是"高性能网站"Souders 。 这是对主题的很好介绍。

我建议你使用实际CSS文件的MD5哈希,而不是手动更改版本。

所以你的网址就像是


http://mysite.com/css/[md5_hash_here]/style.css

你仍然可以使用重写规则去除哈希,但好处是现在你可以将缓存策略设置为"永久缓存",因为如果URL是相同的,这意味着文件没有改变。

然后,你可以编写一个简单的shell脚本来计算文件的哈希并更新你的标记( 你可能想要将它移动到单独的文件中,以便包含) 。

只要在每次CSS改变时运行那个脚本,你就好了。 浏览器将只在更改文件时重新加载文件。 如果你做了一个编辑,然后撤销它,你就没有必要弄清楚你需要返回哪个版本才能让访问者不 re-download 。

你可以在 css/js导入的结尾放置 ?foo=1234,将 1234更改为你喜欢的任何内容。 查看一个示例的html源代码。

这个想法就是? 在请求中丢弃/忽略参数,你可以在推出新版本时更改该号码。


用regard来到底是怎么影响 caching, 注意: 有一些辩论 我相信它的一般要点是获取请求,带有或者不带参数应该可以缓存,所以上面的解决方案应该可以。

但是,这取决于站点服务器是否要遵守规范和浏览器所使用的部分,因为它可以直接运行并请求一个新版本。

我听说过"自动版本控制"。 最常用的方法是在URL中包含文件的静态 mtime,并用重写处理程序或者 URL confs去除它:

另请参见:

不知道为什么你要用这么多的痛苦来实现这个解决方案。

如果得到修改的文件时间戳并将它作为 QueryString 附加到文件中,你需要做的就是

在PHP中,我将这样做:


<link rel="stylesheet" href="mycss.css?v=<?php echo filemtime('mycss.css')?>"/>

filemtime是一个返回文件修改时间戳的PHP函数。

不要使用 foo.css? version=1 浏览器不应该用获取变量来缓存 url 。 根据 http://www.thinkvitamin.com/features/webapps/serving-javascript-fast,虽然 IE 和 Firefox 忽略该,Opera 和Safari不 ! 使用 foo.v1234. css,并使用重写规则去除版本号。

在 RewriteRule end,处需要一个小小的更新为js或者css文件,这些文件包含一个点表示法 versioning. 比如 json-1.3.js 。

我添加了一个圆点否定类 [^.] 到 正规表达式 所以。号。 被忽略。


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

有趣的文章。阅读了所有的答案,结合了"伪"查询字符串( 我不确定为什么大家都不愿意使用这个)的事实,我猜解决方案( 这就消除了对apache重写规则的需求,如接受的答案) 是计算CSS文件内容( 而不是文件日期时间)的一个简短的散列。

这将导致以下结果:


<link rel="stylesheet" href="/css/base.css?[hash-here]" type="text/css"/>

当然,日期时间解决方案也可以在编辑CSS文件的情况下完成任务,但我认为它是关于CSS文件内容而不是文件时间戳的,所以为什么要把这些混淆起来?

...