2011年11月30日,星期三

Avoiding bugs from cached JavaScript和CSS双色球推荐一注 in SharePoint

这篇文章很详细,所以在这里’执行摘要– 如果您将自定义JavaScript / CSS双色球推荐一注等存储在SharePoint下的某个位置’s ‘layouts’双色球推荐一注夹(或将其手动上传到站点内的库中),请确保每次更新时URL都会更改。通常使用网址中的querystring参数来完成此操作,例如/_layouts/MyProject/JS/MyScript.js修订版= 2011.11.20.1

2011年12月5日更新: 更正-如果您仅使用Microsoft的ScriptLink控件向页面添加JavaScript引用,则如果将.js双色球推荐一注存储在页面中,则该问题不会对您造成影响“layouts”。但是,如果将它们存储在库中,并且每次双色球推荐一注更改时都没有回收IIS,这将会自动发生-对于WSP部署,它应该自动发生。“layouts”当然。您可能会发现,并非总是可以单独使用ScriptLink-例如,在我当前的项目中,我们在JavaScript双色球推荐一注之间有很多依赖关系,并且ScriptLink不允许您指定自定义.js双色球推荐一注应以的顺序(顺序)已添加到页面(AFAIK)。因此,尽管您的行程可能会有所不同,但我认为本文的主旨仍然适用于许多人。无论如何,非常感谢Mahmoud Hamed在下面的评论中发现了测试结果中的缺陷-我已经更新了下表。

对于我从事的大多数项目,我更喜欢将JavaScript / CSS等存储在SharePoint根双色球推荐一注夹下某处的双色球推荐一注系统上(例如“14”),通常在“layouts”双色球推荐一注夹-对我来说,这些双色球推荐一注通常是“site infrastructure”因此对于整个平台的品牌/功能至关重要。也就是说,在某些情况下,我’d走另一条路线并将其存储在网站集中(因此存储在内容数据库中)– these would be:

  • 对于仅适用于一个网站(例如团队网站)的CSS / JS双色球推荐一注
  • 沙盒解决方案

当我概述这些原因时 这个问题的答案,投票显示出很多同意,总体上,我看到很多人都在使用这种方法。但是,我’ve最近注意到,许多人没有意识到关键的陷阱– 和it’如此重要,我’我不断感到惊讶’s doesn’不再讨论。问题是 end users 不 seeing updated JavaScript和CSS双色球推荐一注 following a recent code deployment。好吧,好吧,我对文章标题有些作弊–实际上,问题不是SharePoint特有的’s “layouts”双色球推荐一注夹(甚至是IIS),当我说“JavaScript和CSS双色球推荐一注”,我的意思是说JavaScript / CSS /图像/音频/视频,实际上是大多数静态双色球推荐一注。但是,嘿,有时以SharePoint的方式来组织主题是提醒人们网络的一般行为也适用于我们的最佳方法‘special’SharePoint类型。似乎许多人可能会错过这些内容,因为他们专注于某些超酷的SharePoint功能区开发,并且在技术阅读方面,我认为’可以公平地说,许多人几乎只关注SharePoint内容。

问题

和许多生活一样’最简单的陷阱,这一陷阱是如此容易陷入。请记住,它仅适用于进行一定程度的自定义(例如品牌/自定义代码)并将双色球推荐一注存储在双色球推荐一注系统上的SharePoint项目–如果这两件事不’不适用于您,问题完全出在Microsoft上,他们会处理双色球推荐一注的问题,因此’没什么好担心的。否则,请想象以下内容:

  1. 开发人员对一些自定义代码进行了更新–先前部署的双色球推荐一注将更新。让’s say we’重新部署一些更新的JavaScript和CSS。
  2. 关联的WSP部署到SharePoint,并且双色球推荐一注在场中的所有Web服务器上更新。
  3. 用户只有进行硬刷新(CTRL + F5)才能看到Javascript / CSS的更改。 Worse still, they could experience 脚本 bugs or broken formatting which could make the application completely unusable.

这种情况通常会导致经常听到的问题“嗯,如果您执行CTRL + F5会怎样?”。当然,对于与开发人员联系的测试用户来说,这一切都很好。在生产中’对于组织的其余部分肯定不是很好–奇怪的是,要求30,000名信息工作者进行CTRL + F5在企业中进展不佳!在Internet / WCM场景中情况变得更好– would you 听到站点用户的JavaScript错误或CSS错误?该消息实际上是否会传达给实施团队(’记得,可能是 看到事件日志中的错误(来自此内容)?还是用户会去别的地方?

原因

发生这种情况的原因是因为第一次请求双色球推荐一注时,Web服务器(当然,这里是IIS,但对大多数服务器也是如此)使用HTTP标头为双色球推荐一注提供服务,该标头指定可以长时间缓存该双色球推荐一注。为了“layouts”双色球推荐一注夹,默认为31536000秒(1年):

CacheControlHeader
浏览器和代理通常会遵循此要求,因此在后续页面请求中,此双色球推荐一注将从‘临时网络双色球推荐一注’ on the user’的计算机或用户与服务器之间的代理。当然,如果没有此功能,网页加载速度将大大降低。我的测试表明,通常,内容数据库提供的双色球推荐一注没有使用相同的标头提供,因此更新会立即显示。然而,事实证明 SharePoint 2010(可能更早)将使用功能部署的双色球推荐一注与手动上传到同一库的双色球推荐一注的处理方式不同. My table below 在 tempts to explain most of my testing 和results:

位置 启用Blob缓存? 结果 笔记
样式库(发布站点) 没有
样式库(发布站点)
样式库(发布站点) 是的(现在已达到最大年龄) 按功能添加
样式库(发布站点) 是的(现在已达到最大年龄) 问题 手动添加到库
版面 脚本链接 DID添加查询字符串?rev = q%2Fb304kubfwrNJVD%2BdYdxg%3D%3D 但不清楚何时更新–双色球推荐一注更改时不!
版面 没有 问题 无论如何,BLOB缓存仅与内容数据库中的双色球推荐一注相关
定制图书馆 问题 手动添加到库
定制图书馆 按功能添加

Conclusions 和notes:

  • 该问题适用于‘layouts’或库中的双色球推荐一注 没有使用功能中的模块标签部署的(或至少是通过浏览器上传的)
    • N.B.我确实确实在Reflector中进行了挖掘,以找到此行为的根源,但是没有’t find it.
  • 对于JavaScript双色球推荐一注,它不会’不管双色球推荐一注如何添加到页面(例如 脚本链接 控制或普通<script> tag)
  • BLOB缓存不做任何更改
  • 沙盒解决方案或服务器场解决方案未做任何更改
  • 注意–已在SharePoint 2010 RTM(旧)和SharePoint 2010 SP1 + 八月 CU(在撰写本文时为全新)上进行了测试

对于受影响的情况,为避免浏览器/代理尽管双色球推荐一注被更新而仍缓存双色球推荐一注,无论双色球推荐一注链接到何处,只需在每个部署中添加/更改查询字符串值。因此,而不是像这样:

  • /_layouts/MyProject/JS/MyScript.js

..我们需要类似以下内容之一:

  • /_layouts/MyProject/JS/MyScript.js修订版= 1.0.0.0
  • /_layouts/MyProject/JS/MyScript.js修订版= 2011.11.20.1

参数可以有任何名称(尽管‘rev’ or ‘revision’是很常见的),但重要的是在每次修改时都以某种方式对其进行更改/增加。如果你’重新增加程序集版本(使用 AssemblyFileVersion 而不是主要版本号 记住),那么使用相同的值可能是合适的–在我当前的项目中,我们在某些地方执行此操作*(稍后会详细介绍),以便我们不要’不必记住手动增加上述链接。实际上,我们使用代码来读取当前的程序集双色球推荐一注版本,并将其附加为‘Rev’querystring值(此值将是TFS自动生成的当前内部版本的内部版本号)。当然,要权衡一下,您可能会强迫用户在更新后的第一时间重新下载双色球推荐一注。’t actually changed – but it’比有错误更安全。顺便说一句,您可能已经注意到Microsoft通过指向CSS / JS双色球推荐一注的链接来执行此操作–它们的值将在Service Pack /累积更新等中更新:

SharePoint2010_JavaScriptLinks

试图以更好的方式解决问题

因此,我们可以通过将querystring添加到链接到CSS / JS双色球推荐一注的任何URL上来解决问题,太好了!但是,在许多情况下,这意味着在每次部署之前,请记住在Visual Studio中的所有具有指向这些双色球推荐一注链接的位置上进行查找/替换。这不是’t ideal –在我们当前的项目中,这可以是母版页,用户控件,使用 ClientScriptManager 和许多其他位置。理想的情况是,如果所有这些问题都能在每次发行时得到照顾!

我没有’t spent too much time on this, but in our project we do use a solution for CSS files 在 least. All 我们的CSS files are emitted to the page 使用 SharePoint’s CSS注册链接 控制项–这意味着所有链接都是由一个控件生成的,这给我们带来了方便‘funnel’我们可以修改。因此,我们只是从 链接 控件,并且在我们的自定义类中,我们重写链接以使‘Rev’参数。使用的值与 AssemblyFileVersion 我们的‘core’程序集(也承载此控件),即CI流程会针对每个发行版进行更新。当然,您可以使用任何喜欢的方案:

   1: public class CacheSafeCssLinkControl : 链接
   2: {
   3:     protected override void Render(HtmlTextWriter output)
   4:     {  
   5:         使用 (HtmlTextWriter tempWriter = new HtmlTextWriter(new StringWriter()))
   6:         {
   7:             base.Render(tempWriter);
   8:             string html = tempWriter.InnerWriter.ToString();
   9:             if (!string.IsNullOrEmpty(html))
  10:             {
  11:                 html = html.ToLower().Replace(".css\"", string.Format(".css?Rev={0}\"", Core.Common.Utilities.GetAssemblyFileVersion(Assembly.GetExecutingAssembly())));   
  12:             }
  13:             output.Write(html);
  14:         }
  15:     }
  16: }

因此,这非常适合CSS双色球推荐一注。但是其他双色球推荐一注,特别是JavaScript呢?好吧,这里’在我们遇到障碍的地方– unfortunately Microsoft.SharePoint.WebControls.ScriptLink (JavaScript链接的等效控件)是密封的,因此我们可以’不要使用相同的方法。有趣的是,如果您很乐意使用反射(也许有一些缓存),则可以添加‘Rev’参数使用与我使用的相同技术 消除大型JS双色球推荐一注以优化SharePoint 2010 Internet网站 –因为链接的集合存储在 HttpContext.Current.Items, 那里’无需将Microsoft换出,就可以在将链接写入页面之前对其进行修改’s control.

I’d可能对此感到满意,但至少在我们项目中的真正问题是,JavaScript也倾向于通过其他途径添加到页面上,例如 ClientScriptManager 和<script> tags. We’d需要更新(大型)代码库以专用 脚本链接 以便我们有一个更有效的渠道。尽管如此,它仍使我对将来的工作方式有一个想法-但从长远来看,如果Microsoft会很好’自己的控件提供了一种添加消除缓存的查询字符串的方法。

概要

开发人员在开发过程中愉快地使用CTRL + F5,’经常会被忽略,最终用户将面临同样的问题,即默认情况下看不到更新的CSS和JavaScript双色球推荐一注。显然,这可能导致各种问题,包括如果页面HTML结构已更改但未使用相应的JavaScript的JavaScript错误。该问题主要在此类双色球推荐一注存储在‘layouts’双色球推荐一注夹,但有趣的是,双色球推荐一注也被手动上载到库中(至少在SharePoint 2010中)。关键是确保每次双色球推荐一注更新时URL都会更改,并且因为在那里查询字符串就足够了’无需实际重命名双色球推荐一注。最终它没有’无论您如何更改查询字符串值,是否’与CI关联的简单手动更新或自动化程度更高的过程。

10条评论:

马克·威尔逊说过...

It'还值得一提的是,IIS可能具有超出您在代码中执行的操作的缓存头。

必须对Fiddler进行良好的检查,并确定响应管道的哪个阶段正在设置标头。为了增加可伸缩性,我看到在几天之内设置了过期期限的站点,这些站点严重影响了升级应用程序的能力。

有时在升级过程中更改IIS缓存指令可以缓解这种情况。

马哈茂德·哈默德(Mahmoud Hamed)说过...

克里斯,你好
在我阅读了您的帖子并阅读了本节之后“ScriptLink DID添加查询字符串?rev = q%2Fb304kubfwrNJVD%2BdYdxg%3D%3D,但不清楚何时更新–双色球推荐一注更改时不”。我反映了ScriptLink和CssLink控件以查看它们如何呈现url,并且发现它们使用此方法。“SPUtility.MakeBrowserCacheSafeLayoutsUrl”which add the “rev” based on the file content so when you update the file the 转速 is changed. So just to make this work you need to add your files under the _layout folder do update reset IIS 和your url will be updated. I hope that this fix your problem.

李·戴尔说过...

克里斯,好帖子,不过一个问题。使用Blob缓存并显式设置max-age超时是否可以解决此问题?

我的意思是说您只在晚上部署,最大使用期限设置为一天。然后,当您的用户第二天到来时,他们的浏览器缓存将过期吗?

只是考虑一种解决问题的OOTB方法。

梅尔·洛塔(Mel Lota)说过...

克里斯,你好

很棒的帖子,我最近在我的一个项目中解决了同样的问题'm当前正在使用-不可否认不是SharePoint,但显然适用相同的原则。我最终通过使用中的FileUpdate任务将其集成到构建过程中'MSBuild社区任务'在部署时在每个母版页上的静态资源上更新查询字符串版本。 FileUpdate任务非常酷,因为它需要使用正则表达式来匹配路径:

http://geekswithblogs.net/mnf/archive/2009/07/03/msbuild-task-to-replace-content-in-text-files.aspx

干杯

克里斯·奥'Brien说过...

@标记,

同意-SharePoint'自己的缓存标题'layouts'目录是在IIS中添加的(不是通过任何内部SharePoint代码添加的),这是在SharePoint在IIS中创建网站时全部配置的。

不确定在部署前更改指令的想法是否有效。考虑到六个月前(并且此后从未访问过)的用户即使您使用了此技术,仍会收到陈旧双色球推荐一注,因为六个月前收到的标头说"cache for 1 year"。也许在其他情况下它很有用。

谢谢,

克里斯。

克里斯·奥'Brien说过...

@Mahmoud,

出色的侦探工作!我重新测试并看到了相同的行为。我认为这对于某些人来说可能会大大改变这个问题,很快我'将相应地更新文章。

然而, 有趣的是,'不能帮助我们的项目,因为我们不't仅将ScriptLink用于所有我们的JavaScript引用(我们使用ClientScriptManager + direct<script>也可以通过DelegateControl标记)。这是因为我们的JS双色球推荐一注中有一些依赖项, '只能使用ScriptLink控件来表达这些内容。也许我们错过了一些东西,但如果不是这样,我认为混合参考模型可能很常见-这意味着我的论点仍然存在。

谢谢,有很大的贡献!

克里斯。

克里斯·奥'Brien说过...

@李

我看到了您的想法,但不幸的是没有(我也对此进行了测试,请参见上面的表格)。实际上这是有道理的,因为重要的是双色球推荐一注时的标头 原来 服务(但是很久以前)。

干杯,

克里斯。

克里斯·奥'Brien说过...

@梅尔

真好知道这是否可以处理双色球推荐一注内容,因此只在绝对需要时才更改查询字符串(以便用户获得全部的缓存好处)吗?

谢谢,

克里斯。

安德斯·拉斯克(Anders Rask)说过...

显然,如果将CSS双色球推荐一注放置在1033 /样式或类似语言的特定双色球推荐一注夹下,而不是在_Layouts /样式下,则?rev =仅由CssRessources附加

月泪说过...

旧帖子,但应在此处添加,因为这在搜索排名中非常高。

Make use of SPUtility.MakeBrowserCacheSafeLayoutsUrl in SharePoint 2013: http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.utilities.sputility.makebrowsercachesafelayoutsurl.aspx