一个伴随ASP.NET从1.0到4.0的OutputCache Bug介绍 |
本文标签:OutputCache,Bug 我们先来一睹这个Bug的风采! 在一个.aspx文件中增加OutputCache设置,代码如下: 复制代码 代码如下: <%@ OutputCache Duration="300" VaryByParam="*"%> 上面的设置表示:缓存5分钟,根据不同的查询字符串更新缓存 。Location使用的是默认值Any,也就是可以在浏览器、代理服务器、Web服务器三个地方进行缓存,在Response Headers中的体现就是Cache-Control:public, max-age=300 。(如果你要用CDN加速,Cache-Control就要用public) 。 然后,我们在Firefox浏览器中访问这个页面,并打开Firebug,见下图: 第一次访问,返回状态码为"200 OK",正常 。这里Response Headers中的Vary:Accept-Encoding是因为IIS启用“动态内容压缩”产生的,如果不启用,就不会出现 。 这时缓存应该被建立起来了,我们按F5刷新一下浏览器,看一下结果,见下图: 第二次访问,返回状态码为"304 Not Modified",浏览器缓存生效,这也是我们期望的 。 但是,请注意一下上图中的Vary:*,它会让浏览器的缓存失效,我们再按一下F5验证一下 。 果然,浏览器缓存失效,返回状态码变回了200 OK 。缓存时间有5分钟呢,第三次就失效了,这样的结果显然不是我们期望的 。 上面的测试是在Web服务器上IIS启用动态内容压缩(dynamic content compression)的情况下进行的,如果关闭动态内容压缩,每次请求返回都是200 OK,Vary都是星号 。也就是说浏览器游览缓存根本没起作用 。 Bug欣赏完毕,我们进行第二个测试 。 将OutputCache的VaryByParam属性值设置为none: 复制代码 代码如下: <%@ OutputCache Duration="600" VaryByParam="none"%> 测试结果显示,浏览器第一次请求之后,接下来在缓存时间内,服务器的响应都是"304 Not Modified",这才是我们想要的效果 。 但是,在实际应用中,我们使用VaryByParam="none"很少,用的更多的是为VaryByParam指定对应的值 。 所以这个Bug影响很大,增加了服务器负担,浪费了带宽 。 Bug相关信息 在微软的官方文档ASP.NET 4 Breaking Changes中专门提到了这个bug —— "Output Caching Changes to Vary * HTTP Header":
从上面的文档中我们可以知道这个Bug的历史: 在ASP.NET 1.0时,如果在OutputCache中设置Location="ServerAndClient",在ASP.NET在响应时会浏览器发送Vary:* HTTP header 。 在ASP.NET 1.1时,微软针对这个Bug,提供一个专门的方法System.Web.HttpCachePolicy.SetOmitVaryStar(bool omit),通过SetOmitVaryStar(true)修改HTTP header,去掉Vary:* 。 在ASP.NET 4时,微软郑重地宣布从根本上解决了这个问题 。 而且,文档中提到这个bug只会出现在Location="ServerAndClient"时 。 可是,我用ASP.NET 4的实测试情况是:不仅Location="ServerAndClient"时的Bug没有解决,而且Location="Any"时也会出现同样的Bug 。 解决方法 解决方法很简单,只要用ASP.NET 1.1时代提供的System.Web.HttpCachePolicy.SetOmitVaryStar(bool omit)就能解决问题,只需在Page_Load中添加如下代码: 复制代码 代码如下: protected void Page_Load(object sender, EventArgs e) { Response.Cache.SetOmitVaryStar(true); } 相关文档 ASP.NET caching tests find a bug with VaryByParam How to cache asp.net web site for better performance Microsoft Connect: The ServerAndClient parameter with the OutputCache page directive does not cache on the client, without code 小结 微软那么有钱,有那么多天才程序员,可是Bug也很难避免,可见开发优秀的软件是多么具有挑战性的工作! 补充 ASP.NET MVC 中不存在这个问题 。 |