关于缓存:如何强制客户端刷新JavaScript文件?

关于缓存:如何强制客户端刷新JavaScript文件?

How can I force clients to refresh JavaScript files?

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

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

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


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

例如:

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

I assume at this point that there isn't a better way than find-replace to increment these"version numbers" in all of the script tags?

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

它看起来像这样:

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

当然,总会有像这样的更好的解决方案。


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

因此,我做了stuff_123.js而不是stuff.js?123

我在apache中使用mod_redirect(我认为)到have stuff_*.jsstuff.js


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

之前

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

之后(强制重装)

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

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


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

例如,

vendor.a7561fb0e9a071baadb9.js
main.b746e3eb72875af2caa9.js

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


在我发布(参考css)http://www.stefanhayden.com/blog/2006/04/03/css-caching-hack/之后,我的同事刚刚找到了对该方法的引用。很高兴看到其他人正在使用它,它似乎工作。我假设在这一点上,没有比find-replace更好的方法来增加所有脚本标签中的这些"版本号"?


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

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

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


使用版本GET变量来阻止浏览器缓存。

?v=AUTO_INCREMENT_VERSION附加到网址的末尾可防止浏览器缓存 - 避免使用任何和所有缓存的脚本。


在PHP中:

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

在HTML中:

1
<script type="text/javascript" src="<?php latest_version('/a-o/javascript/almanacka.js'); ?>">< /script>

这个怎么运作:

在HTML中,按照您的要求编写filepath和名称,但仅限于函数。
PHP获取文件的filetime并返回最新更改的filepath+name+"?"+time


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

1
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true"/>

Dave Paquette有一个很好的例子和解释缓存清除(页面底部)Cache Busting


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

1
<script src="~/JsFilePath/JsFile.js?v=@DateTime.UtcNow.ToString()">

虽然它是特定于框架的,但Django 1.4具有这种功能,其工作方式与上述答案中"greenfelt"网站的链接类似。


fileV1.js上使用file.js?V=1的优点是您不需要在服务器上存储多个版本的JavaScript文件。

我在file.js?V=1中看到的问题是,在使用新版本的库实用程序时,您可能在另一个JavaScript文件中有依赖代码。

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


以下为我工作:

1
2
3
4
5
6
7
8
<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>

一个简单的方法。
编辑htaccess

1
2
3
4
5
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]

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

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


推荐阅读