如何强制客户端刷新JavaScript文件?

问题描述 投票:539回答:23

我们目前正在进行私人测试,因此仍在进行相当快速的更改,尽管显然随着使用量开始增加,我们将放慢这一过程。话虽这么说,我们遇到的一个问题是,在我们用新的JavaScript文件推出更新之后,客户端浏览器仍然使用文件的缓存版本,但他们看不到更新。显然,在支持调用中,我们可以简单地通知他们执行ctrlF5刷新以确保他们从服务器获取最新文件,但最好在此之前处理它。

我们当前的想法是简单地将版本号附加到JavaScript文件的名称上,然后在进行更改时,增加脚本上的版本并更新所有引用。这绝对可以完成工作,但更新每个版本的引用可能会变得很麻烦。

我确信我们不是第一个处理这个问题的人,我想我会把它扔给社区。在更新代码时,如何确保客户更新缓存?如果您使用上述方法,您是否正在使用简化更改的流程?

javascript caching versioning
23个回答
501
投票

据我所知,一个常见的解决方案是在脚本的src链接中添加一个?<version>

例如:

<script type="text/javascript" src="myfile.js?1500"></script>

我假设在这一点上,没有比find-replace更好的方法来增加所有脚本标签中的这些“版本号”?

你可能有一个版本控制系统为你做这个吗?大多数版本控制系统都有办法在登记时自动注入修订号。

它看起来像这样:

<script type="text/javascript" src="myfile.js?$$REVISION$$"></script>

当然,总有更好的解决方案,如this one


3
投票

jQuery函数getScript还可用于确保每次加载页面时确实加载了js文件。

我就是这样做的:

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();
    }
    ...
}

检查$(document).ready(function(){ $.getScript("../data/playlist.js", function(data, textStatus, jqxhr){ startProgram(); }); }); 的功能

默认情况下,$ .getScript()将缓存设置设置为false。这会将带时间戳的查询参数附加到请求URL,以确保浏览器在每次请求时都下载脚本。


3
投票

我们一直在为用户创建一个SaaS并为他们提供一个脚本以附加到他们的网站页面中,并且无法附加脚本版本,因为用户会将脚本附加到他们的网站以获取功能,我无法强迫他们每次更新脚本时更改版本

因此,我们找到了一种在每次用户调用原始脚本时加载较新版本脚本的方法

提供给用户的脚本链接

http://api.jquery.com/jQuery.getScript/

脚本文件

<script src="https://thesaasdomain.com/somejsfile.js" data-ut="user_token"></script>

说明:

用户已经在他们的网站上附加了提供给他们的脚本,我们使用jQuery选择器检查附加脚本的唯一令牌是否存在,如果没有,则使用更新的令牌(或版本)动态加载它

这两次调用相同的脚本可能是性能问题,但它确实解决了强制脚本无法从缓存加载而不将版本放在给用户或客户端的实际脚本链接中的问题

免责声明:如果性能在您的情况下是一个大问题,请不要使用。


1
投票

一种解决方案是在获取资源时将带有时间戳的查询字符串附加到URL。这利用了以下事实:浏览器不会缓存从带有查询字符串的URL中获取的资源。

您可能根本不希望浏览器不缓存这些资源;您希望缓存它们的可能性更大,但是您希望浏览器在文件可用时获取该文件的新版本。

最常见的解决方案似乎是在文件名本身中嵌入时间戳或修订号。这是一项更多的工作,因为您的代码需要被修改以请求正确的文件,但这意味着,例如,您的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 } 版本7(即snazzy_javascript_file.js)缓存在浏览器上,直到您发布版本8,然后您的代码更改为获取snazzy_javascript_file_7.js


1
投票

使用版本snazzy_javascript_file_8.js变量来阻止浏览器缓存。

GET附加到您的网址末尾可防止浏览器缓存 - 避免任何和所有缓存的脚本。


1
投票

我的同事刚刚在?v=AUTO_INCREMENT_VERSION发布(参考css)后发现了对该方法的引用。很高兴看到其他人正在使用它,它似乎工作。我假设在这一点上,没有比find-replace更好的方法来增加所有脚本标签中的这些“版本号”?


1
投票

虽然它是特定于框架的,但Django 1.4有http://www.stefanhayden.com/blog/2006/04/03/css-caching-hack/,其工作方式与this functionailty中'greenfelt'网站的链接类似。


1
投票

在PHP中:

above answer

在HTML中:

function latest_version($file_name){
    echo $file_name."?".filemtime($_SERVER['DOCUMENT_ROOT'] .$file_name);
}

这个怎么运作:

在HTML中,编写<script type="text/javascript" src="<?php latest_version('/a-o/javascript/almanacka.js'); ?>">< /script> 和名称,但仅在函数中。 PHP获取文件的filepath并返回最新更改的filetime


1
投票

通过标记帮助程序缓存ASP.NET Core中的Busting将为您处理此问题,并允许您的浏览器保留缓存的脚本/ css,直到文件更改为止。只需将标签helper asp-append-version =“true”添加到脚本(js)或链接(css)标记中:

filepath+name+"?"+time

Dave Paquette有一个很好的例子和解释缓存破坏(页面底部)<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true"/>


1
投票

现在的常见做法是生成内容哈希码作为文件名的一部分,以强制浏览器特别是IE重新加载javascript文件或css文件。

例如,

vendor.a7561fb0e9a071baadb9.js main.b746e3eb72875af2caa9.js

它通常是构建工具(如webpack)的工作。如果你有人想尝试使用webpack,这里有更多Cache Busting


1
投票

在asp.net mvc中,您可以将@ DateTime.UtcNow.ToString()用于js文件版本号。版本号自动更改日期,您强制客户端浏览器自动刷新js文件。我使用这种方法,这是很好的。

details

83
投票

将当前时间附加到URL确实是一种常见的解决方案。但是,如果需要,您还可以在Web服务器级别进行管理。可以将服务器配置为为javascript文件发送不同的HTTP标头。

例如,要强制将文件缓存不超过1天,您将发送:

Cache-Control: max-age=86400, must-revalidate

对于测试版,如果您想强制用户始终获取最新信息,您可以使用:

Cache-Control: no-cache, must-revalidate

0
投票

最简单的解决方案根本不要让浏览器缓存。将当前时间(以毫秒为单位)附加为查询。

(你仍然处于测试阶段,所以你可以为不优化性能做出合理的判断。但是YMMV在这里。)


0
投票

<script src="~/JsFilePath/[email protected]()"></script> 上使用file.js?V=1的优点是您不需要在服务器上存储多个版本的JavaScript文件。

我在fileV1.js中遇到的麻烦是,在使用新版本的库实用程序时,您可能在另一个JavaScript文件中有依赖代码。

为了向后兼容,我认为将file.js?V=1用于新页面并让现有页面使用jQuery.1.3.js要好得多,直到您准备好升级旧页面(如有必要)。


0
投票

一个简单的方法。编辑htaccess

jQuery.1.1.js

0
投票

以下为我工作:

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]

42
投票

Google Page-Speed:不要在URL中包含静态资源的查询字符串。大多数代理,最着名的是Squid从版本3.0开始,不会使用“?”来缓存资源。即使响应中存在Cache-control:public标头,也会在其URL中显示。要为这些资源启用代理缓存,请从对静态资源的引用中删除查询字符串,而是将参数编码为文件名本身。

在这种情况下,您可以将版本包含在URL ex:http://abc.com/v1.2 / script.js中,并使用apache mod_rewrite将链接重定向到http://abc.com/script.js。更改版本时,客户端浏览器将更新新文件。


33
投票

此用法已被弃用:qazxsw poi

这个答案只晚了6年,但我在很多地方都没有看到这个答案...... HTML5引入了用于解决这个问题的https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache。我发现我写的新服务器代码正在崩溃存储在人们浏览器中的旧javascript,所以我想找到一种方法来使他们的javascript过期。使用如下所示的清单文件:

Application Cache

每次希望用户更新其缓存时,都会生成带有新时间戳的文件。作为旁注,如果你添加它,浏览器将不会重新加载(即使用户刷新页面),直到清单告诉它。


25
投票

如何将filesize添加为加载参数?

CACHE MANIFEST
# Aug 14, 2014
/mycode.js

NETWORK:
*

因此,每次更新文件时,“filever”参数都会更改。

更新文件和更新结果的文件大小相同时怎么样?有什么可能性?


18
投票

并非所有浏览器都使用“?”缓存文件在里面。我做了什么来确保它尽可能地被缓存,我在文件名中包含了该版本。

因此,而不是<script type='text/javascript' src='path/to/file/mylibrary.js?filever=<?=filesize('path/to/file/mylibrary.js')?>'></script> ,我做了stuff.js?123

我用stuff_123.js(我认为)在apache到mod_redirecthave stuff_*.js


12
投票

对于ASP.NET页面,我使用以下内容

之前

stuff.js

之后(强制重装)

<script src="/Scripts/pages/common.js" type="text/javascript"></script>

添加DateTime.Now.Ticks非常有效。


6
投票

对于ASP.NET,我认为下一个解决方案具有高级选项(调试/发布模式,版本):

通过这种方式包含的Js或Css文件:

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

Global.JsPostfix和Global.CssPostfix在Global.asax中通过以下方式计算:

<script type="text/javascript" src="Scripts/exampleScript<%=Global.JsPostfix%>" />
<link rel="stylesheet" type="text/css" href="Css/exampleCss<%=Global.CssPostfix%>" />

4
投票

如果您正在生成链接到JS文件的页面,则一个简单的解决方案是将文件的最后修改时间戳附加到生成的链接。

这与Huppie的答案非常相似,但适用于没有关键字替换的版本控制系统。它也比附加当前时间更好,因为即使文件根本没有改变,这也会阻止缓存。

© www.soinside.com 2019 - 2024. All rights reserved.