如何强制浏览器重新加载缓存的CSS和JavaScript文件
我注意到一些浏览器(特别是Firefox和)非常热衷于使用.css和.js文件的缓存副本,甚至在浏览器会话之间也是如此。当您更新其中一个文件时,这会导致出现问题,但用户的浏览器会继续使用缓存的副本 当文件发生更改时,强制用户浏览器重新加载文件的最优雅方式是什么 理想情况下,该解决方案不会强制浏览器在每次访问页面时重新加载文件如何强制浏览器重新加载缓存的CSS和JavaScript文件,javascript,css,caching,auto-versioning,Javascript,Css,Caching,Auto Versioning,我注意到一些浏览器(特别是Firefox和)非常热衷于使用.css和.js文件的缓存副本,甚至在浏览器会话之间也是如此。当您更新其中一个文件时,这会导致出现问题,但用户的浏览器会继续使用缓存的副本 当文件发生更改时,强制用户浏览器重新加载文件的最优雅方式是什么 理想情况下,该解决方案不会强制浏览器在每次访问页面时重新加载文件 我发现你的建议很有用。事实证明,这有一个术语:自动版本控制 我在下面贴了一个新的答案,它是我原来的解决方案和约翰的建议的结合 SCdF提出的另一个想法是在文件中附加一个伪
我发现你的建议很有用。事实证明,这有一个术语:自动版本控制 我在下面贴了一个新的答案,它是我原来的解决方案和约翰的建议的结合 SCdF提出的另一个想法是在文件中附加一个伪造的查询字符串。(一些Python代码自动将时间戳用作伪查询字符串,这是错误的。)
但是,对于浏览器是否会缓存带有查询字符串的文件,存在一些讨论。(请记住,我们希望浏览器缓存文件并在将来访问时使用它。我们只希望它在文件发生更改时再次获取文件。)此解决方案是用PHP编写的,但它应该可以轻松地适应其他语言 原始的
.htaccess
regex可能会导致像json-1.3.js
这样的文件出现问题。解决方案是,只有在末尾正好有10位数字时才重写。(因为10位数字涵盖了从2001年9月9日到2286年11月20日的所有时间戳。)
首先,我们在.htaccess中使用以下重写规则:
RewriteEngine on
RewriteRule ^(.*)\.[\d]{10}\.(css|js)$ $1.$2 [L]
现在,我们编写以下PHP函数:
/**
*给定一个文件,即/css/base.css,将其替换为包含
*文件的mtime,即/css/base.1221534296.css。
*
*@param$file要加载的文件。必须是绝对路径(即。
*从斜杠开始)。
*/
函数自动_版本($file)
{
如果(strpos($file,“/”)!==0 | |!file_存在($_服务器['DOCUMENT_ROOT'].$file))
返回$file;
$mtime=filemtime($\服务器['DOCUMENT\u ROOT'].$file);
返回preg_replace(“{\\.([^./]+)$}”、“$mtime.\$1”、$file);
}
现在,无论您将CSS包括在何处,都可以从以下内容进行更改:
为此:
<link rel="stylesheet" href="<?php echo auto_version('/css/base.css'); ?>" type="text/css" />
此解决方案是用PHP编写的,但它应该很容易适应其他语言
原始的.htaccess
regex可能会导致像json-1.3.js
这样的文件出现问题。解决方案是,只有在末尾正好有10位数字时才重写。(因为10位数字涵盖了从2001年9月9日到2286年11月20日的所有时间戳。)
首先,我们在.htaccess中使用以下重写规则:
RewriteEngine on
RewriteRule ^(.*)\.[\d]{10}\.(css|js)$ $1.$2 [L]
现在,我们编写以下PHP函数:
/**
*给定一个文件,即/css/base.css,将其替换为包含
*文件的mtime,即/css/base.1221534296.css。
*
*@param$file要加载的文件。必须是绝对路径(即。
*从斜杠开始)。
*/
函数自动_版本($file)
{
如果(strpos($file,“/”)!==0 | |!file_存在($_服务器['DOCUMENT_ROOT'].$file))
返回$file;
$mtime=filemtime($\服务器['DOCUMENT\u ROOT'].$file);
返回preg_replace(“{\\.([^./]+)$}”、“$mtime.\$1”、$file);
}
现在,无论您将CSS包括在何处,都可以从以下内容进行更改:
为此:
<link rel="stylesheet" href="<?php echo auto_version('/css/base.css'); ?>" type="text/css" />
您可以将?foo=1234
放在CSS/JavaScript导入的末尾,将1234更改为您喜欢的任何内容。以堆栈溢出HTML源代码为例
这里的想法是,?
参数在请求时被丢弃/忽略,您可以在推出新版本时更改该数字
注意:关于这究竟是如何影响缓存的,存在一些争论。我相信它的一般要点是,无论是否有参数,请求都应该是可计算的,因此上述解决方案应该是可行的
然而,这取决于web服务器决定是否要遵守规范的这一部分以及用户使用的浏览器,因为它可以直接要求一个新版本。您可以在CSS/JavaScript导入的末尾添加?foo=1234
,将1234更改为您喜欢的任何版本。以堆栈溢出HTML源代码为例
这里的想法是,?
参数在请求时被丢弃/忽略,您可以在推出新版本时更改该数字
注意:关于这究竟是如何影响缓存的,存在一些争论。我相信它的一般要点是,无论是否有参数,请求都应该是可计算的,因此上述解决方案应该是可行的
然而,这取决于web服务器决定是否要遵守规范的这一部分以及用户使用的浏览器,因为它可以直接要求一个新版本。我听说过这叫做“自动版本控制”。最常用的方法是将静态文件的修改时间包含在URL中的某个位置,并使用重写处理程序或URL配置将其删除:
另见:
我听说过这叫做“自动版本控制”。最常用的方法是将静态文件的修改时间包含在URL中的某个位置,并使用重写处理程序或URL配置将其删除:
另见:
如果将会话id添加为JavaScript/CSS文件的伪参数,则可以强制执行“会话范围缓存”:
<link rel="stylesheet" src="myStyles.css?ABCDEF12345sessionID" />
<script language="javascript" src="myCode.js?ABCDEF12345sessionID"></script>
如果需要版本范围的缓存,可以添加一些代码来打印文件日期或类似内容。如果您使用的是Java,则可以使用自定义标记以优雅的方式生成链接
<link rel="stylesheet" src="myStyles.css?20080922_1020" />
<script language="javascript" src="myCode.js?20080922_1120"></script>
如果将会话id添加为伪id,则可以强制执行“会话范围缓存”
http://mysite.com/css/[md5_hash_here]/style.css
script("/main.css")
<link rel="stylesheet" type="text/css" href="/main.css?1221842734">
/styles/screen.css
/styles/screen.css?v=1234
/v/1234/styles/screen.css
body {
background-image: url('images/happy.gif');
}
/v/1234/styles/images/happy.gif
<link rel="stylesheet" href="/css/base.css?[hash-here]" type="text/css" />
RewriteRule ^(.*)\.[^.][\d]+\.(css|js)$ $1.$2 [L]
/**
* Extend filepath with timestamp to force browser to
* automatically refresh them if they are updated
*
* This is based on Kip's version, but now
* also works on virtual hosts
* @link http://stackoverflow.com/questions/118884/what-is-an-elegant-way-to-force-browsers-to-reload-cached-css-js-files
*
* Usage:
* - extend your .htaccess file with
* # Route for My_View_Helper_AutoRefreshRewriter
* # which extends files with there timestamp so if these
* # are updated a automatic refresh should occur
* # RewriteRule ^(.*)\.[^.][\d]+\.(css|js)$ $1.$2 [L]
* - then use it in your view script like
* $this->headLink()->appendStylesheet( $this->autoRefreshRewriter($this->cssPath . 'default.css'));
*
*/
class My_View_Helper_AutoRefreshRewriter extends Zend_View_Helper_Abstract {
public function autoRefreshRewriter($filePath) {
if (strpos($filePath, '/') !== 0) {
// Path has no leading '/'
return $filePath;
} elseif (file_exists($_SERVER['DOCUMENT_ROOT'] . $filePath)) {
// File exists under normal path
// so build path based on this
$mtime = filemtime($_SERVER['DOCUMENT_ROOT'] . $filePath);
return preg_replace('{\\.([^./]+)$}', ".$mtime.\$1", $filePath);
} else {
// Fetch directory of index.php file (file from all others are included)
// and get only the directory
$indexFilePath = dirname(current(get_included_files()));
// Check if file exist relativ to index file
if (file_exists($indexFilePath . $filePath)) {
// Get timestamp based on this relativ path
$mtime = filemtime($indexFilePath . $filePath);
// Write generated timestamp to path
// but use old path not the relativ one
return preg_replace('{\\.([^./]+)$}', ".$mtime.\$1", $filePath);
} else {
return $filePath;
}
}
}
}
<link href="mycss.css?v=<?= filemtime('mycss.css') ?>" rel="stylesheet">
example.css?randomNo = Math.random()
<script type="text/javascript" src="Scripts/exampleScript<%=Global.JsPostfix%>" />
<link rel="stylesheet" type="text/css" href="Css/exampleCss<%=Global.CssPostfix%>" />
protected void Application_Start(object sender, EventArgs e)
{
...
string jsVersion = ConfigurationManager.AppSettings["JsVersion"];
bool updateEveryAppStart = Convert.ToBoolean(ConfigurationManager.AppSettings["UpdateJsEveryAppStart"]);
int buildNumber = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Revision;
JsPostfix = "";
#if !DEBUG
JsPostfix += ".min";
#endif
JsPostfix += ".js?" + jsVersion + "_" + buildNumber;
if (updateEveryAppStart)
{
Random rand = new Random();
JsPosfix += "_" + rand.Next();
}
...
}
(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);
}
})();
<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>
exec('git rev-parse --verify HEAD 2> /dev/null', $gitLog);
echo ' <script src="/path/to/script.js"?v='.$gitLog[0].'></script>'.PHP_EOL;
<script src="{{ asset('/js/your.js?v='.filemtime('js/your.js')) }}"></script>
<link rel="stylesheet" href="{{asset('css/your.css?v='.filemtime('css/your.css'))}}">
<link rel="stylesheet" href="assets/css/your.css?v=1577772366">
$(window).load(function() {
location.reload(true);
});
<link rel="stylesheet" href="~/css/custom.css?d=@(System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/css/custom.css")).ToString(),"[^0-9]", ""))" />
<script type="text/javascript" src="~/js/custom.js?d=@(System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/js/custom.js")).ToString(),"[^0-9]", ""))"></script>
<script src="<%= Page.ResolveClientUrlUnique("~/js/custom.js") %>" type="text/javascript"></script>
public static class Extension_Methods
{
public static string ResolveClientUrlUnique(this System.Web.UI.Page oPg, string sRelPath)
{
string sFilePath = oPg.Server.MapPath(sRelPath);
string sLastDate = System.IO.File.GetLastWriteTime(sFilePath).ToString();
string sDateHashed = System.Text.RegularExpressions.Regex.Replace(sLastDate, "[^0-9]", "");
return oPg.ResolveClientUrl(sRelPath) + "?d=" + sDateHashed;
}
}
<script src="https://jessietessie.github.io/google-translate-token-generator/google_translate_token_generator.js" integrity="sha384-muTMBCWlaLhgTXLmflAEQVaaGwxYe1DYIf2fGdRkaAQeb4Usma/kqRWFWErr2BSi" crossorigin="anonymous"></script>
// 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>