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

See*_*ker 29 html javascript

我想在javascript文件源路径的末尾添加一个随机数或时间戳,以便每次页面重新加载时都应下载一个新的副本.

应该是这样的

<script type="text/javascript" src="/js/1.js?v=1234455"/>
Run Code Online (Sandbox Code Playgroud)

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

The*_*Kid 44

方法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>
Run Code Online (Sandbox Code Playgroud)

方法2(AJZane的评论)

小而坚固的包容性.您可以确切地看到JavaScript被触发的位置,并且它比方法1更不可定制(至关重要).

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

  • 这不是太复杂吗?为什么不使用简单的`<script> document.write("<script type ='text/javascript'src ='// site.com/js.js?v="+ Date.now()+"'> <\/SCRIPT>"); </ SCRIPT>` (21认同)

epo*_*och 10

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

如果你担心在加载脚本之前你的javascript执行,你可以使用onload脚本元素的回调(请注意,虽然有一些箍要跳到IE)


LWu*_*urm 8

如果您选择使用日期或随机数附加到您的URI,您将为最终用户提供相同的缓存文件提供服务的机会,可能潜在地暴露出意外的安全风险.显式版本控制系统不会.原因如下:

为什么"随机"和随机数都很糟糕

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

为什么日期或时间戳也不好,但也不差

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

一些罕见但可能的例外情况:

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

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

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

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

  • 用户喜欢重置系统时钟以惹恼您

为什么增量版或独特版本是好的:)

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

你或你的团队应该是唯一一个编辑你的JS文件的人,所以关键的不在于你的文件需要每次都是新鲜的,我需要在它发生变化时提供新的服务.在您的情况下,浏览器缓存并不是一件坏事,但您确实需要告诉最终用户什么时候应该更新.基本上,当您的文件更新时,您希望确保客户端获得更新的副本.有了这个,您还可以恢复到以前版本的代码,而无需担心客户端缓存问题.唯一的缺点是您需要使用尽职调查来确保在更新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>
Run Code Online (Sandbox Code Playgroud)

我要提到的是完整性,如果您要从生成"随机"编号或日期GET变量的旧系统转换为递增版本化系统,请确保您不会跨越任何可能随机生成的文件名称新版本系统.如果有疑问,请在更改方法时为GET变量添加前缀,或者只是一起添加新的GET变量.示例:"foo.js?version = my_prefix_121216"或"foo.js?version = 121216&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>");
});
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是过度工程 (4认同)

Jit*_*oli 5

如果您无法使用用户服务器端代码,则可以使用getScript方法执行相同的操作。

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

参考网址:http : //api.jquery.com/jQuery.getScript/

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