712

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

我们当前的想法是简单地在JavaScript文件的名称上附加一个版本号,然后在进行更改时,增加脚本上的版本并更新所有引用。这无疑完成了任务,但更新每个版本上的引用可能会很麻烦。

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

4
  • stackoverflow.com/questions/118884/…
    – 低估
    评论 2012年1月23日9:50
  • 1
    我已经尝试了下面所有的“答案”,实际上黑客。它们都无法从缓存中删除确切的图像。难怪这个问题666人喜欢(2022-05-28). – 显然,浏览器功能仍然缺失。–服务器端无缓存标头似乎是唯一的方法。
    – 阿凡达
    评论 2022年5月28日11:07
  • 1
    有人试过吗? 评论 2022年5月31日12:21
  • 我认为可以使用电子标签标头,用于在文件内容发生更改时更新缓存。 评论 2023年5月23日20:41

30个答案30

重置为默认值
617

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

例如:

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

此时,我假设没有比find-replace更好的方法来增加所有脚本标记中的这些“版本号”?

你可能有一个版本控制系统为你做这件事?例如,大多数版本控制系统都有一种在签入时自动注入修订号的方法。

它看起来像这样:

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

当然,总有更好的解决方案,比如这个.

15
  • 6
    有人知道IE7是否忽略了这一点吗?当我在IE8可比性视图中测试时,它似乎忽略了附加的数据并使用了缓存的文件。 评论 2011年1月20日20:18
  • 5
    我一直都知道查询字符串是键值对,如?版本=123。谢谢!:) 评论 2012年2月15日11:41
  • 8
    我认为这不是关于更高或更低的版本号,而是关于将附加变量值更改为浏览器还无法缓存的值。
    – 小黄瓜
    评论 2013年8月5日10:43
  • 56
    意识方面:这被认为是一次黑客攻击。此方法诱使浏览器认为正在指定一个新文件,因为它只查看完整的文件名,而不解释它。foo.js?1与名称不同foo.js?2,因此浏览器会认为它们是两个不同的文件。一个缺点是这两个文件将同时存在于用户的缓存中,占用了不必要的空间。 评论 2014年9月18日13:22
  • 19
    @无论您如何处理问题,这两个文件都将缓存在浏览器中。可能是因为它们具有不同的请求参数或不同的路径。所以我不认为这是请求参数方法的缺点。
    – 厚木板
    评论 2016年11月29日18:29
113

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

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

Cache-Control:max-age=86400,必须重新验证

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

缓存控制:无缓存,必须重新验证
8
  • 5
    你能说得更具体些吗?
    – 克雷克
    评论 2012年6月21日7:44
  • 10
    他正在谈论web服务器为每个文件发送的标题。例如,应该可以在Apache中配置。我认为这将是最好的方法 评论 2012年7月25日12:16
  • 4
    你在哪里配置这个?
    – 迭戈
    评论 2016年12月29日16:07
  • 2
    对于开发Web应用程序来说,这可能是一个很好的解决方案。对于一个生产站点,如果您不想让缓存永远失效,那么这不是一个好的解决方案,除非您知道每个目标客户端浏览器都已访问该站点。它让我想到一个潜在的web服务器功能:根据配置的部署日期调整max-age参数。那太棒了。 评论 2017年3月15日13:48
  • Chrome需要这些设置才能正确缓存。如果没有它们,Chrome将永远缓存一个文件。Mozilla使用了更合理的默认值。更多信息请访问:agiletribe.wordpress.com/2018/01/29/caching-for-chrome公司 评论 2018年1月30日23:01
46

Google Page-Speed:不要在静态资源的URL中包含查询字符串。大多数代理,尤其是Squid到3.0版,都不会缓存URL中带有“?”的资源,即使响应中存在cache-control:public标头。要为这些资源启用代理缓存,请从对静态资源的引用中删除查询字符串,并将参数编码到文件名中。

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

2
  • 我试过了?在IE8中,我得到一个javascript错误。Mod重写是一个选项,但在大多数情况下,我们无法对服务器进行太多控制。我更喜欢将版本附加在js文件中,或者为每个版本都有一个文件夹 评论 2014年1月29日20:29
  • @Hắc Huyền Minh:但当脚本需要重新加载时,不应该从代理缓存重新加载。。。 评论 2017年12月11日17:16
37

添加文件大小作为加载参数怎么样?

<script type='text/javascript'src='path/to/file/myllibrary.js?文件服务器=<=文件大小(“path/to/file/mylibrary.js”)?>“></脚本>

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

当你更新文件时,你的更新结果是相同的文件大小,怎么样?可能性有多大?

6
  • 5
    这使用PHP标记,如果使用PHP,这确实是一个好主意。
    – 杰瑟
    评论 2017年4月19日12:31
  • 5
    我认为添加更改日期比文件大小更好:)
    – 马兹
    评论 2017年5月24日9:22
  • 7
    我最初的想法是添加文件的散列,而不是版本。 评论 2017年9月1日17:29
  • 2
    我认为如果添加一个时间戳Unix也可以,对吧?例如“。。。file.js?文件服务器=<=时间()?>
    – 加兰达
    评论 2017年10月6日18:36
  • 4
    使用filemtime($file),它输出文件的时间戳,使用time(),您不能使用缓存,因为它每秒都在更改。 评论 2017年11月28日15:37
37

此用法已被弃用:https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache

这个答案只晚了6年,但我在很多地方都看不到这个答案。。。HTML5已经推出应用程序缓存用来解决这个问题。我发现我正在编写的新服务器代码正在破坏人们浏览器中存储的旧javascript,所以我想找到一种方法让他们的javascript过期。使用如下所示的清单文件:

缓存MANIFEST#2014年8月14日/霉菌.js网络:*

并在每次希望用户更新其缓存时生成带有新时间戳的文件。作为补充说明,如果添加此项,浏览器将重新加载(即使用户刷新页面),直到清单告诉它。

4
22

并非所有浏览器都使用缓存文件'?'为了确保尽可能多地缓存它,我在文件名中包含了版本。

所以不是填充.js?123,我做到了填充_123.js

我用过修改_直接(我认为)在阿帕奇填充_*.js外带填充.js

4
  • 2
    你能详细说明一下你在.htaccess中用mod_redirect做了什么吗? 评论 2011年11月8日6:15
  • 有关此方法的详细说明,请参阅particletree.com/notebook/… 评论 2011年12月6日17:03
  • 如果你能把你的.ht访问答案中的代码供将来参考。 评论 2016年2月29日6:54
  • 4
    哪些浏览器不缓存包含“?”的文件? 评论 2019年6月17日9:08
14

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

例如,

小贩。a7561fb0e9a071baadb9.js文件
主要。b7463年3月72875年2月9日.js文件

这通常是构建工具(如webpack)的工作。这里还有更多细节如果有人想试试你是否在使用webpack。

12

对于ASP。NET页面我正在使用以下内容

之前

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

AFTER(强制重新加载)

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

添加DateTime。现在。滴答声效果很好。

5
  • 36
    这与客户端的所有缓存机制背道而驰。虚拟参数应该替换为类似“{主要版本}”的内容_{次要版本}_{内部编号}_{Revision},对于每个版本来说都是唯一的。
    – 托希德
    评论 2014年11月10日16:58
  • 18
    虽然在开发环境中这可能是一个很好的解决方案,但它不适合生产。这将完全禁用缓存每次加载页面时用于文件。想象一下,每天用一个50Kb文件加载10k页,它代表每天500Mb的Javascript文件。 评论 2016年6月6日12:16
  • @PhilDulac可以将其从Ticks更改为返回日期的字符串值,例如,月份或月份的周。最终它只是向您展示如何使用?v方法 评论 2016年6月15日15:16
  • @亚历克斯确实如此。我只是想警告一下,如果答案中展示的用法进入生产,它可能会产生开发中没有表现出来的影响。 评论 2016年6月15日16:02
  • 2
    确保每天加载一次新副本的一种可能方法是使用'<script src=“/Scripts/pages/common.js?ver<%=DateTime.Now.ToString(“yyyyMMdd”)%>”type=“text/javascript”></script>'。所以它在一天开始时加载一次,然后缓存。 评论 2017年9月13日15:17
8

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

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

<script type=“text/javascript”src=“脚本/exampleScript<%=Global.JsPostfix%>”/><link rel=“stylesheet”type=“text/css”href=“css/exampleCss<%=Global.CssPostfix%>”/>

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

protected void Application_Start(对象发送方,EventArgs e){...string jsVersion=配置管理器。AppSettings[“JsVersion”];bool updateEveryAppStart=转换。ToBoolean(ConfigurationManager.AppSettings[“UpdateJsEveryAppStart”]);int buildNumber=系统。反思。组装。GetExecutingAssembly()。获取名称()。版本。修订;JsPostfix=“”;#如果!调试JsPostfix+=“.min”;#结尾JsPostfix+=“.js?”+jsVersion+“_”+buildNumber;if(updateEveryAppStart){Random rand=新Random();JsPosfix+=“_”+兰特。下一步();}...}
1
  • 我正在使用。勾选(见本页我的答案) 评论 2014年1月23日1:09
7

菲律宾比索:

函数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>

工作原理:

在HTML中,编写文件路径和你的名字一样,但只在函数中。PHP获取文件时间并返回文件路径+名称+“?”+时间最新更改的

6

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

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

1
  • 我喜欢这个解决方案,因为它最容易维护。如果你更新一个.js文件,这就是你需要做的全部。不需要同时更新对文件的任何引用,因为你的代码会自动添加最后更新的时间戳。 评论 2016年6月13日16:44
6

我们一直在为用户创建SaaS,并为他们提供一个脚本以附加在他们的网站页面中,因为用户会将脚本附加到他们的网站上以获得功能,所以不可能在脚本中附加一个版本,我不能每次更新脚本时都强制他们更改版本

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

提供给用户的脚本链接

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

脚本文件

if($('script[src^=“https://thesaasdomain.com/somejsfile.js?“]').长度!==0){init();}其他{loadScript(“https://thesaasdomain.com/somejsfile.js?“+guid());}var loadscript=函数(scriptURL){var head=document.getElementsByTagName('head')[0];var script=document.createElement('script');script.type='text/javascript';script.src=脚本URL;head.appendChild(脚本);}var guid=函数(){返回“xxxxxxxx-xxxx-4xxx-yxxxx-xxxxxxxxxx”。替换(/[xy]/g,函数(c){var r=数学随机数()*16|0,v=c=='x'?r:(r&0x3|0x8);return v.toString(16);});}var init=函数(){//我们的主要代码}

说明:

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

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

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

4

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

我就是这样做的:

$(document).ready(function()){$.getScript(“../data/playlist.js”,函数(数据,textStatus,jqxhr){启动程序();});});

检查以下位置的功能http://api.jquery.com/jquery.getScript/

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

2
  • 9
    如果没有更改,我们需要缓存文件。 评论 2016年1月18日2:45
  • 这会从服务器中获取文件,但不会更新缓存,如果我们想刷新缓存,这将无法实现。
    – 切萨里
    评论 3月15日17:31
4

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

<script src=“~/JsFilePath/[电子邮件保护]()“></script>
2
  • 1
    与其他建议的解决方案一样,这将导致文件永远不会被缓存,这通常是不可取的。只要文件没有更改,您可能希望客户端使用缓存版本,而不是每次都再次下载未更改的文件。 评论 2020年5月23日14:31
  • 1
    出于您的原因,可以使用以下代码缓存版本号为的文件<script src=“~/JsFilePath/JsFile.js?v=@GetAppVersionNumber()”></script>
    – 龙的
    评论 2020年5月27日6:23

我的同事刚刚在我发布(关于css的)帖子后发现了对该方法的引用http://www.stefanhayden.com/blog/2006/04/03/css-caching-hack/。很高兴看到其他人也在使用它,而且它似乎很管用。我认为目前没有比find-replace更好的方法来增加所有脚本标记中的“版本号”?

1
  • 1
    这似乎对.css和.js文件都很有效。
    – TNF公司
    评论 2021年3月9日8:38
2

一种解决方案是在获取资源时将一个包含时间戳的查询字符串附加到URL。这利用了这样一个事实,即浏览器不会缓存从包含查询字符串的URL中获取的资源。

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

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

2

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

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

为了向后兼容,我认为最好使用jQuery.1.3.js并允许现有页面使用jQuery.1.1.js,直到您准备好升级旧页面(如果需要)。

2

使用版本GET(获取)变量以防止浏览器缓存。

附录?v=自动增量版本url的末尾阻止浏览器缓存,避免任何和所有缓存的脚本。

2

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

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

Dave Paquette在这里有一个很好的缓存破解示例和解释(页面底部)缓存中断

2
  • 这在常规ASP中不起作用吗。净利润?我尝试将asp-append-version添加到脚本标记中,浏览器看到的只是与源代码中显示的完全相同的脚本标记,包括asp-apped-version属性。 评论 2017年7月26日20:03
  • 这是一个。与标记帮助程序关联的NET核心属性。它在脚本名称后面附加一个版本,以便服务器/浏览器始终可以看到最新版本并进行下载
    – 科尔文
    评论 2017年7月31日22:42
2

location.reload(true);

看见https://www.w3schools.com/jsref/met_loc_reload.asp

我动态调用这行代码,以确保从web服务器而不是从浏览器的缓存中重新检索javascript,从而避免此问题。

4
  • 添加onload=“location.reload();”到我的表单允许我在刷新后获得新的JS,而不是重新启动我的页面。这是一个更优雅的解决方案。谢谢!
    – ZX9型
    评论 2019年11月6日14:37
  • 谢谢,如果该ip已被识别,但自上次更新后尚未用于登录,请在用户首次登录后在索引页上执行此操作,可以使用此选项进行检查。 评论 2019年11月21日8:25
  • onload=“location.reload(true);”上述操作对我不起作用(使用烧瓶和当前版本的Chrome):w3schools.com/jsref/met_loc_reload.asp 评论 2019年12月30日23:20
  • 这不会为我刷新缓存。调用“location”。Reload(true)“只需重新加载页面,脚本就可以从“内存缓存”中获取。”位置。Reload()'从“磁盘缓存”获取脚本。这两种情况都会得到最新的缓存(旧的)脚本。
    – 切萨里
    评论 3月15日17:38
2

虽然它是特定于框架的,但Django 1.4已经staticfiles应用程序功能其工作方式与上述答案

1

一个简单的方法。编辑htaccess

RewriteEngine开重写数据库/重写命令%{REQUEST_URI}\。(jpe?g|bmp|png|gif|css|js|mp3|ogg)$[NC]重写命令%{QUERY_STRING}^(.+?&v33|)v=33[^&]*(?:&(.*)|)$[NC]重写规则^%{REQUEST_URI}?v=33[R=301,L]
1
  • 1
    这会导致重定向,这是一种性能上的次优但有效的解决方案。 评论 2017年8月1日9:03
1

您可以将文件版本添加到文件名中,使其类似于:

https://www.example.com/script_fv25.js

fv25=>文件版本号25

在您的.htaccess中放置此块,它将从链接中删除版本部分:

RewriteEngine开重写规则(.*)_fv\d+\。(js|css|txt|jpe?g|png|svg|ico|gif)$1.$2[L]

因此,最终的链接将是:

https://www.example.com/script.js
1

前端选项

我做了这个密码明确地对于那些无法更改后端任何设置的用户。在这种情况下,防止超长缓存的最佳方法是:

new Date().getTime()

然而,对于大多数程序员来说,缓存可能需要几分钟或几个小时,因此上面的简单代码最终会迫使所有用户下载“浏览的每个页面”。为了指定此项在不重新加载的情况下保留多长时间,我编写了此代码,并在下面留下了几个示例:

//cache-express-after.js v1函数cacheExpiresAfter(延迟=1,前缀=“”,后缀=“”){//秒let now=new Date().getTime().toString();now=now.substring(now.length-11,10);//删除数十年和毫秒now=parseInt(now/delay).toString();返回前缀+现在+后缀;};//(延迟参数的)示例://值每1秒更改一次var cache=cacheExpiresAfter(1);//查看同步setInterval(函数(){console.log(cacheExpiresAfter(1),new Date().getSeconds()+'s');}, 1000);//值每1分钟更改一次var cache=cacheExpiresAfter(60);//查看同步setInterval(函数(){console.log(cacheExpiresAfter(60),new Date().getMinutes()+'m:'+new Date().getSeconds()+'s');}, 1000);//值每5分钟更改一次var cache=cacheExpiresAfter(60*5);//或300//值每1小时更改一次var cache=cacheExpiresAfter(60*60);//或3600//值每3小时更改一次var cache=cacheExpiresAfter(60*60*3);//或10800//值每1天更改一次var cache=cacheExpiresAfter(60*60*24);//或86400//用法示例:let head=document.head ||document.getElementsByTagName('head')[0];let script=document.createElement('script');script.setAttribute('src','//unpkg.com/[电子邮件保护]/dist/sweetallert.min.js'+cacheExpiresAfter(60*5,'?');head.append(脚本);//这有效吗?let waitSwal=设置间隔(函数(){if(窗口.swal){clearInterval(waitSwal);swal('脚本成功注入',Script.outerHTML);};}, 100);
1
<脚本>var版本=new Date().getTime();var script=document.createElement(“script”);script.src=“app.js?=”+版本;document.body.appendChild(脚本);</script>

如果有人已经在上面的大量答案中发布了它,请随意删除它。

0

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

(您仍处于测试阶段,因此您可以合理地说明不优化性能的理由。但这里是YMMV。)

1
  • 14
    我想这是一个糟糕的解决方案。如果您没有参加BETA测试,并且发布了重要更新,该怎么办?
    – d-_-b日
    评论 2010年8月24日7:42
0

以下内容对我很有用:

<头部><元字符集=“UTF-8”><meta http-equiv=“cache-control”content=“no-cache,must-revalization,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=“1980年1月1日星期二1:00:00 GMT”/><meta http-equiv=“pragma”content=“no-cache”/></头>
0

如果您使用的是PHP和Javascript,那么以下内容应该适用于您,尤其是在您对文件进行多次更改的情况下。所以,每次你不能改变它的版本。因此,其思想是在PHP中创建一个随机数,然后将其指定为JS文件的一个版本。

$fileVersion=rand();<script src=“addNewStudent.js?v=<?php echo$fileVersion;?>”></script>
0

关于在HTTP头中设置Cache-Control的建议对我来说非常有效。下面是在Apache 2.4中实现这一点需要采取的步骤。

首先通过运行以下命令启用headers模块(在Linux中)a2enmod标头或者(在Windows中)编辑Apache配置文件(例如C:\Apache24\conf\httpd.conf)并取消注释行

LoadModule headers_module modules/mod_headers.so加载模块头

假设,作为一个示例,我们想为所有人添加一天的缓存限制.js文件.css文件文件夹。为此,我们编辑网站的Apache配置文件并添加以下代码:

#.js和.css文件的客户端缓存持续一天<FilesMatch“\.(js|css)$”>标题集Cache-Control“max-age=86400,必须重新验证”</FilesMatch>

一天的限制转换为秒(86400)。

进一步假设,我们有一个子目录,名为mystatic公司其中包含大量不变的JavaScript文件。出于客户端性能的原因,我们可能希望禁用这些文件的时间限制。为此,我们将在Apache配置文件中添加更多行:

<目录/PATHTOWW/mystatic/><FilesMatch“\.(js)$”>标题未设置Cache-Control</FilesMatch></目录>

这将关闭的Cache-Control标头.js文件目录中的文件mystatic公司(请注意,应将“PATHTOWW”替换为该目录的实际路径。)

-1

您可以使用.htaccess来完成此操作

在.htaccess文件中添加以下行:

#禁用缓存<IfModule mod_headers.c><FilesMatch“\.js$”>标题集Cache-Control“no-store,max-age=0”</FilesMatch></If模块>

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.