如何强制客户端刷新 JavaScript 文件?
-
09-06-2019 - |
题
我们目前正在进行私人测试版,因此仍在进行相当快速的更改,尽管显然随着使用量开始增加,我们将放慢这一过程。话虽这么说,我们遇到的一个问题是,在我们推出新 JavaScript 文件的更新后,客户端浏览器仍然使用该文件的缓存版本,并且看不到更新。显然,在支持电话中,我们可以简单地通知他们做 控制键F5 刷新以确保他们从服务器获取最新文件,但最好在此之前处理此问题。
我们当前的想法是简单地将版本号附加到 JavaScript 文件的名称上,然后在进行更改时,增加脚本上的版本并更新所有引用。这肯定可以完成工作,但更新每个版本的参考资料可能会很麻烦。
因为我确信我们不是第一个处理这个问题的人,所以我想我会把它扔给社区。当您更新代码时,如何确保客户端更新其缓存?如果您使用上述方法,您是否使用了简化更改的流程?
解决方案
据我所知,一个常见的解决方案是添加一个 ?<version>
到脚本的 src 链接。
例如:
<script type="text/javascript" src="myfile.js?1500"></script>
我认为此时没有比查找替换更好的方法来增加所有脚本标签中的这些“版本号”?
您可能有版本控制系统为您做这件事吗?例如,大多数版本控制系统都有一种在签入时自动注入修订号的方法。
它看起来像这样:
<script type="text/javascript" src="myfile.js?$$REVISION$$"></script>
当然,总是有更好的解决方案,例如 这个.
其他提示
将当前时间附加到 URL 确实是一种常见的解决方案。但是,如果您愿意,您也可以在 Web 服务器级别进行管理。服务器可以配置为发送 javascript 文件的不同 HTTP 标头。
例如,要强制缓存文件不超过 1 天,您可以发送:
Cache-Control: max-age=86400, must-revalidate
对于测试版,如果您想强制用户始终获取最新版本,您可以使用:
Cache-Control: no-cache, must-revalidate
谷歌页面速度:不要在静态资源的 URL 中包含查询字符串。大多数代理人,最著名的是通过版本3.0的鱿鱼,不会用“?”来缓存资源。即使在缓存控制中,在他们的URL中也是如此:响应中存在公共标头。要为这些资源启用代理缓存,请从对静态资源的引用中删除查询字符串,并将参数编码到文件名本身中。
在这种情况下,您可以将版本包含到 URL 中,例如: http://abc.com/v1.2/script.js 并使用 apache mod_rewrite 将链接重定向到 http://abc.com/script.js. 。当您更改版本时,客户端浏览器将更新新文件。
此用法已被弃用: https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache
这个答案只晚了6年,但我在很多地方都没有看到这个答案......HTML5引入了 应用程序缓存 这是用来解决这个问题的。我发现我正在编写的新服务器代码正在破坏人们浏览器中存储的旧 JavaScript,因此我想找到一种方法来使他们的 JavaScript 过期。使用如下所示的清单文件:
CACHE MANIFEST
# Aug 14, 2014
/mycode.js
NETWORK:
*
并在每次您希望用户更新其缓存时生成带有新时间戳的文件。附带说明一下,如果您添加此内容,浏览器将 不是 重新加载(即使用户刷新页面),直到清单告诉它。
添加文件大小作为加载参数怎么样?
<script type='text/javascript' src='path/to/file/mylibrary.js?filever=<?=filesize('path/to/file/mylibrary.js')?>'></script>
因此,每次更新文件时,“filever”参数都会更改。
当您更新文件并且更新结果相同的文件大小时怎么样?可能性有多大?
并非所有浏览器都会缓存文件 '?' 在里面。为了确保尽可能多地缓存它,我在文件名中包含了版本。
所以而不是 stuff.js?123
, ,我做了 stuff_123.js
我用了 mod_redirect
(我认为)在 apache 中 have stuff_*.js
去 stuff.js
对于 ASP.NET 页面,我使用以下内容
前
<script src="/Scripts/pages/common.js" type="text/javascript"></script>
之后(强制重新加载)
<script src="/Scripts/pages/common.js?ver<%=DateTime.Now.Ticks.ToString()%>" type="text/javascript"></script>
添加 DateTime.Now.Ticks 效果很好。
对于 ASP.NET,我想下一个具有高级选项的解决方案(调试/发布模式、版本):
通过这种方式包含的Js或Css文件:
<script type="text/javascript" src="Scripts/exampleScript<%=Global.JsPostfix%>" />
<link rel="stylesheet" type="text/css" href="Css/exampleCss<%=Global.CssPostfix%>" />
Global.JsPostfix 和 Global.CssPostfix 在 Global.asax 中通过以下方式计算:
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();
}
...
}
如果您要生成链接到 JS 文件的页面,一个简单的解决方案是将文件的上次修改时间戳附加到生成的链接中。
这与 Huppie 的答案非常相似,但适用于版本控制系统,无需关键字替换。它也比附加当前时间更好,因为即使文件根本没有更改,这也会阻止缓存。
我们一直在为用户创建一个 SaaS,并为他们提供一个脚本以附加到他们的网站页面中,但不可能附加带有该脚本的版本,因为用户会将脚本附加到他们的网站以获取功能,我不能强迫他们每次更新脚本时更改版本
因此,我们找到了一种方法,在每次用户调用原始脚本时加载较新版本的脚本
提供给用户的脚本链接
<script src="https://thesaasdomain.com/somejsfile.js" data-ut="user_token"></script>
脚本文件
if($('script[src^="https://thesaasdomain.com/somejsfile.js?"]').length !== 0) {
init();
} else {
loadScript("https://thesaasdomain.com/somejsfile.js?" + guid());
}
var loadscript = function(scriptURL) {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = scriptURL;
head.appendChild(script);
}
var guid = function() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
var init = function() {
// our main code
}
解释:
用户已在其网站中附加了提供给他们的脚本,我们使用 jQuery 选择器检查脚本附加的唯一令牌是否存在,如果不存在,则使用较新的令牌(或版本)动态加载它
这会调用同一脚本两次,这可能会导致性能问题,但它确实解决了强制脚本不从缓存加载而不将版本放入提供给用户或客户端的实际脚本链接中的问题
免责声明:如果性能对您来说是一个大问题,请不要使用。
jQuery 函数 getScript 还可以用于确保每次加载页面时确实加载了 js 文件。
我就是这样做的:
$(document).ready(function(){
$.getScript("../data/playlist.js", function(data, textStatus, jqxhr){
startProgram();
});
});
检查该功能 http://api.jquery.com/jQuery.getScript/
默认情况下,$.getScript() 将缓存设置设置为 false。这会将带时间戳的查询参数附加到请求 URL,以确保浏览器每次请求时都会下载脚本。
一种解决方案是在获取资源时将带有时间戳的查询字符串附加到 URL。这利用了这样一个事实:浏览器不会缓存从包含查询字符串的 URL 中获取的资源。
不过,您可能根本不希望浏览器不缓存这些资源;您更有可能希望缓存它们,但您希望浏览器在文件的新版本可用时获取该文件。
最常见的解决方案似乎是在文件名本身中嵌入时间戳或修订号。这需要做更多的工作,因为需要修改您的代码才能请求正确的文件,但这意味着,例如你的版本7 snazzy_javascript_file.js
(IE。 snazzy_javascript_file_7.js
) 会缓存在浏览器上,直到您发布版本 8,然后您的代码更改为 fetch snazzy_javascript_file_8.js
反而。
使用版本 GET
变量以防止浏览器缓存。
追加 ?v=AUTO_INCREMENT_VERSION
网址末尾可防止浏览器缓存 - 避免任何和所有缓存的脚本。
我的同事在我发布(参考 css)后立即找到了对该方法的引用 http://www.stefanhayden.com/blog/2006/04/03/css-caching-hack/. 。很高兴看到其他人正在使用它并且它似乎有效。我认为此时没有比查找替换更好的方法来增加所有脚本标签中的这些“版本号”?
在 PHP:
function latest_version($file_name){
echo $file_name."?".filemtime($_SERVER['DOCUMENT_ROOT'] .$file_name);
}
在 超文本标记语言:
<script type="text/javascript" src="<?php latest_version('/a-o/javascript/almanacka.js'); ?>">< /script>
怎么运行的:
在 HTML 中,编写 filepath
和名称如您所愿,但仅在函数中。PHP 得到 filetime
文件并返回 filepath+name+"?"+time
最新变化的
ASP.NET Core 中的缓存清除通过标记帮助器将为您处理此问题,并允许您的浏览器保留缓存的脚本/CSS,直到文件更改。只需将标签助手 asp-append-version="true" 添加到您的脚本 (js) 或链接 (css) 标签中:
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true"/>
Dave Paquette 在此处提供了一个很好的缓存清除示例和解释(页面底部) 缓存清除
现在的常见做法是生成内容哈希代码作为文件名的一部分,以强制浏览器(尤其是 IE)重新加载 javascript 文件或 css 文件。
例如,
小贩。a7561fb0e9a071baadb9.js
主要的。b746e3eb72875af2caa9.js
这通常是 webpack 等构建工具的工作。这里有更多 细节 如果有人想尝试一下你是否正在使用 webpack。
最简单的解决方案?根本不要让浏览器缓存。附加当前时间(以毫秒为单位)作为查询。
(您仍处于测试阶段,因此您可以为不优化性能提出合理的理由。但YMMV在这里。)
使用的优点 file.js?V=1
在...之上 fileV1.js
的优点是您不需要在服务器上存储多个版本的 JavaScript 文件。
我看到的麻烦 file.js?V=1
问题是您可能在另一个 JavaScript 文件中包含依赖代码,这些代码在使用新版本的库实用程序时会中断。
为了向后兼容,我认为使用更好 jQuery.1.3.js
为您的新页面并让现有页面使用 jQuery.1.1.js
, ,直到您准备好升级旧页面(如有必要)。
一种简单的方法。编辑 htaccess
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} \.(jpe?g|bmp|png|gif|css|js|mp3|ogg)$ [NC]
RewriteCond %{QUERY_STRING} !^(.+?&v33|)v=33[^&]*(?:&(.*)|)$ [NC]
RewriteRule ^ %{REQUEST_URI}?v=33 [R=301,L]
在 asp.net mvc 中你可以使用 @DateTime.UtcNow.ToString() 为js文件版本号。版本号随日期自动更改,并强制客户端浏览器自动刷新 js 文件。我使用这个方法并且效果很好。
<script src="~/JsFilePath/JsFile.js?v=@DateTime.UtcNow.ToString()"></script>
以下对我有用:
<head>
<meta charset="UTF-8">
<meta http-equiv="cache-control" content="no-cache, must-revalidate, post-check=0, pre-check=0" />
<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />
</head>