如何将时间戳附加到标签 url 中的 javascript 文件以避免<script>缓存



我想在中的javascript文件源路径的末尾附加一个随机数或时间戳,这样每次重新加载页面时都应该下载一个新的副本。

它应该像

<script type="text/javascript" src="/js/1.js?v=1234455"/>

我如何生成和追加这个数字?这是一个简单的HTML页面,因此不能使用任何PHP或JSP相关代码

方法1

可以通过这种方式添加许多扩展,包括异步包含和脚本延迟。许多广告网络和高流量网站都使用这种方法。

<script type="text/javascript">
(function(){ 
var randomh=Math.random();
var e = document.getElementsByTagName("script")[0];
var d = document.createElement("script");
d.src = "//site.com/js.js?x="+randomh+"";
d.type = "text/javascript"; 
d.async = true;
d.defer = true;
e.parentNode.insertBefore(d,e);
})();
</script>

方法2(AJZane的评论)

小而稳健的包容性。您可以准确地看到JavaScript的激发位置,而且它的可定制性(到目前为止)不如方法1。

<script>document.write("<script type='text/javascript' src='//site.com
/js.js?v=" + Date.now() + "'></script>");</script>

如果您选择使用日期或随机数附加到URI,您将为最终用户提供获得相同缓存文件的机会可能会暴露意外的安全风险。明确的版本控制系统不会。原因如下:

为什么"随机"和随机数都是坏的

对于随机数,您不能保证以前不会生成相同的随机数并将其提供给该用户。较小的"随机"数集或较差的算法比其他算法更频繁地提供相同的结果,生成相同字符串的可能性更大。一般来说,如果你依赖JavaScript随机方法,请记住它是伪随机的,如果你试图依赖唯一性,比如说你的一个脚本中的XSS漏洞补丁或类似的东西,它也可能会带来安全隐患。我们不希望Johnny在Hacker先生访问的那天,通过AJAX调用一个不再受信任的第三方脚本,获得旧的缓存和未修补的JS文件。

为什么日期或时间戳也很糟糕,但没有那么糟糕

将日期视为"唯一"标识符,JavaScript将从客户端生成Date对象。根据日期格式的不同,意外缓存的可能性可能会有所不同。单独的日期(20160101)允许一整天的潜在缓存问题,因为早上的访问会导致foo.js?date=20160101,晚上的访问也是如此。相反,如果指定倒数第二(20160101000000),那么最终用户调用相同GET参数的几率会降低,但仍然存在。

少数罕见但可能的例外情况:

  • 在大多数时区,时钟每年重置一次(落后)

  • 由于某种原因在重新启动时重置本地时间的计算机

  • 自动网络时间同步,使您的时钟向后调整几秒/分钟,只要您的本地时间从服务器时间关闭

  • 旅行时调整时区设置(IIS上的宇航员每隔几分钟就要经过一个区域……我们不要降低他们的浏览体验:p)

  • 用户喜欢重置他们的系统时钟来干扰你

为什么增量或唯一版本控制是好的:)

对于仅限fontend的解决方案,我的建议是设置一个显式版本,每次更改文件时,您或您的团队成员可以简单地对其进行硬编码。完全按照你在问题的同一代码中所做的手动操作将是一种很好的做法。

你或你的团队应该是唯一编辑JS文件的人,所以关键不是你的文件每次都需要更新,我只需要在更改时更新。浏览器缓存在您的情况下并不是一件坏事,但您确实需要告诉最终用户WHEN它应该更新。本质上,当您的文件更新时,您希望确保客户端获得更新的副本。这样,您还可以恢复到以前版本的代码,而不用担心客户端缓存问题。唯一的缺点是,当你更新JS文件时,你需要进行尽职调查,以确保你真正更新了版本号。记住,某些事情不是自动化的,并不意味着它一定是糟糕的做法或糟糕的形式。让你的解决方案适合你的情况和你现有的资源。

如果可能的话,我建议使用类似语义版本控制规则的形式,通过查看文件名(假设开发过程中没有人篡改版本号)来轻松识别向后或破坏兼容性。除非您有一个奇怪的用例,否则没有充分的理由每次都强制向客户端提供一个新的副本。

使用本地存储在客户端自动增加版本

如果您所追求的是为您自动生成唯一版本号的前端方法,这样您就不必显式设置它,那么您就必须实现某种本地存储方法来跟踪并自动递增文件版本。我在下面展示的解决方案将失去语义版本控制的能力,并且如果用户知道如何清除本地存储,也有可能被重置。然而,考虑到您的选择仅限于客户端解决方案,这可能是您的最佳选择:

<script type="text/javascript">
(function(){
/**
* Increment and return the local storage version for a given JavaScript file by name
* @param  {string} scriptName  Name of JavaScript file to be versioned (including .js file extension)
* @return {integer}            New incremented version number of file to pass to .js GET parameter
*/
var incrementScriptVer = function(scriptName){
var version = parseInt(localStorage.getItem(scriptName));
// Simple validation that our item is an integer
if(version > 0){
version += 1;
} else {
// Default to 1
version = 1;
}
localStorage.setItem(scriptName, version);
return version;
};
// Set your scripts that you want to be versioned here
var scripts = ['foo.js', 'bar.js', 'baz.js'];
// Loop through each script name and append our new version number
scripts.map(function(script){
var currentScriptVer = incrementScriptVer(script);
document.write("<script language='text/javascript' type='text/javascript' src='http://yoursite.com/path/to/js/" + script + "?version=" + currentScriptVer + " '></script>");
});
})();
</script>

为了完整起见,我要提到的是,如果您正在从一个生成"随机"编号或日期的GET变量的旧系统转换为一个递增版本的系统,请确保您不会使用新的版本控制系统跳过任何可能随机生成的文件名。如果有疑问,请在更改方法时为GET变量添加前缀,或者简单地将一个新的GET变量一起添加。示例:"foo.js?version=my_prefix_121216"或"foo.js?version=1121216&version_system=incremental">

通过AJAX调用和其他方法实现自动化版本控制(如果可以进行后端开发)

就我个人而言,我喜欢远离本地存储选项。如果选项可用,它将是"最佳"解决方案。尝试让后端开发人员创建一个端点来跟踪JS文件版本,您可以始终使用对该端点的响应来确定您的版本号。如果你已经在使用像Git这样的版本控制,你可以选择让你的Dev-Ops团队将你的版本控制绑定到你的提交版本,以进行一些非常好的集成。

RESTful GET端点的jQuery解决方案可能看起来像:

var script = "foo.js";
// Pretend this endpoint returns a valid JSON object with something like { "version": "1.12.20" }
$.ajax({
url: "//yoursite.com/path/to/your/file/version/endpoint/" + script
}).done(function(data) {
var currentScriptVer = data.version;
document.write("<script language='text/javascript' type='text/javascript' src='http://yoursite.com/path/to/js/" + script + "?version=" + currentScriptVer + " '></script>");
});

通过document.createElement('script')动态插入脚本,然后在设置URL时,可以使用new Date().getTime()附加额外的参数。

如果您担心javascript在加载脚本之前执行,可以使用脚本元素的onload回调(注意,IE需要跳过一些环节)

如果您不能使用服务器端代码,那么您可以使用getScript方法来执行同样的操作。

$(document).ready(function(){
var randomNum = Math.ceil(Math.random() * 999999);
var jsfile = 'scripts/yourfile.js?v=' + randomNum;
$.getScript(jsfile, function(data, textStatus, jqxhr) { });
});

引用URL:http://api.jquery.com/jQuery.getScript/

(请不要忘记标记为答案。)

手动或使用jQuery加载脚本http://api.jquery.com/jQuery.getScript/.它还提供了防止篡改的选项

您可以用纯Javascript 替换执行此操作的脚本源

// get first script
var script = document.getElementsByTagName('script')[0]
var new = document.createElement("script");
// add the source with a timestamp
new.src = 'yoursource.js?' + new Date.getTime().toString();
new.type = 'text/javascript'
script.parentNode.insertBefore(new,script);

如果不是字母数字,则替换正则表达式Date.protype.toISOString()

var today = new Date();
"MyFile_" + today.toISOString().replace(/[^w]/g, "") + ".pdf"

MyFile_20191021T173426146Z.pdf

旧帖子,但这里只有一行:

<script src="../Scripts/source/yourjsname.js?ver<%=DateTime.Now.Ticks.ToString()%>" type="text/javascript"></script>

最新更新