用程序实现HTTP压缩和缓存

    用Asp.Net开发Web应用时,为了减少请求次数和流量,可以在IIS里配置gzip压缩以及开启客户端缓存。园子里已经有很多文章介绍了如何在IIS里开启压缩和缓存,但我想搞清楚该如何自己写代码来实现http压缩或者缓存,这样做的原因主要有下面两点:

1.IIS的版本不同,启用IIShttp压缩的方式也不同,IIS7还好一些,但对于IIS6来说,稍微麻烦一点;

2.如果我把应用部署在虚拟空间上,是没办法去设置虚拟主机的IIS

     所以了解如何用程序实现http压缩和缓存还是很有必要的。

实现压缩:在.netSystem.IO.Compression命名空间里,有两个类可以帮助我们压缩response中的内容:DeflateStreamGZIPStream,分别实现了deflategzip压缩,可以利用这两个类来实现http压缩。

实现缓存:通过在responseheader中加入ETagExpiresLastModified,即可启用浏览器缓存。

     下面我们创建一个小小的Asp.net Mvc2 App,然后逐步为它加入压缩和缓存。

     首先新建一个Asp.net Mvc2web application,建好后整个solution如下图:

   

实现缓存

     要缓存的文件包括jscss、图片等静态文件。我在上面已经提到了,要使浏览器能够缓存这些文件,需要在responseheader中加入相应的标记。要做到这一点,我们首先要使我们的程序可以控制到这些文件的response输出。用mvccontroller是一个不错的方法,所以首先在Global.asax.cs中加入下面的路由规则:

 
  

上面加粗的代码增加了一条url路由规则,匹配以Cache开头的url,并且指定了ControllerCache。参数action指定请求的是css还是jsresourceName指定请求的资源的文件名,versioncssjs文件的版本。加入这个version参数的目的是为了刷新客户端的缓存,当cssjs文件做了改动时,只需要在url中改变这个version值,客户端浏览器就会认为这是一个新的资源,从而请求服务器获取最新版本。

可能你会有疑问,加了这个路由规则之后,在View中引用cssjs的方法是不是得变一下才行呢?没错,既然我要用程序控制jscss的输出,那么在View中引用jscss的方式也得做些改变。引用jscss的常规方法如下:

这种引用方式是不会匹配到我们新加的路由的,所以在View中,要改成如下的方式:

 

下面我们先实现这个CacheController。添加一个新的Controller,名为CacheController,并为它添加两个Action:

 
  
 
  

 

添加的两个ActionCssJs,分别用于处理对cssjs的请求。其实对css和对js请求的逻辑是差不多的,都是读取服务器上相应资源的文件内容,然后发送到客户端,不同的只是cssjs文件所在的目录不同而已,所以我们添加一个类来处理对资源的请求。

Controllers下添加一个类,名为ResourceHandler,代码如下:

 
  
 
  
 
  
 
  

 

在上面的代码中,ProecesRequest负责处理对cssjs的请求,先判断资源是否在客户端浏览器中缓存了,如果没有缓存,再读取cssjs文件,并在header中加入和缓存相关的header,发送到客户端。

在这里有必要解释一下IsCachedOnBrowser这个方法。你可能会质疑这个方法是否有存在的必要:既然浏览器已经缓存了某个资源,那么在缓存过期之前,浏览器就不会再对服务器发出请求了,所以这个方法是不会被调用的。这个方法一旦被调用,那说明浏览器在重新请求服务器,再次读取资源文件不就行了吗,为什么还要判断一次呢?

其实,即使客户端缓存的资源没有过期,浏览器在某些时候也会重新请求服务器的,例如按F5刷新的时候。用户按了浏览器的刷新按钮之后,浏览器就会重新请求服务器,并利用LastModifiedETag来询问服务器资源是否已经改变,所以IsCachedOnBrowser这个方法就是用来处理这种情况的:读出Request中的If-Modified-Since,然后和资源的最后修改时间做比较,如果资源没被修改,则直接返回304的代码,告知浏览器只需要从缓存里取就行了。

下面在CacheController中使用这个ResourceHandler。先增加一个CacheResult的类,继承自ActionReult

 
  
 
  
 
  

修改CacheController如下:

 
  
 
  

可以看到,由于version只是用来改变url更新缓存的,对于我们处理资源的请求是没用的,所以我们在这两个Action中都忽略了这两个参数。

缓存的逻辑到这里就完成大部分了,下面我们为UrlHelper加两个扩展方法,方便我们在View中使用。增加一个UrlHelperExtensions的类,代码如下:

 
  
 
  

version配置在web.configappSettings节点下。然后修改Site.Master中对cssjs的引用:

这样,缓存基本上算是完成了,但我们还漏了一个很重要的问题,那就是css中对图片的引用。假设在site.css中有下面一段css

然后再访问~/Home/Index时就会有一个404的错误,如下图:

clip_image004

由于css中对图片的链接采用的是相对路径,所以浏览器自动计算出http://localhost:37311/Cache/Css/12/images/bg.jpg这个路径,但服务器上并不存在这个文件,所以就有了404的错误。解决这个问题的方法是再加一个路由规则:

这样就把对~/Cache/Css/12/images/bg.jpg的请求路由到了CacheControllerCssImage这个Action上。下面我们为CacheController加上CssImage这个Action

 
  
 
  

然后修改ResourceHandler类,让他支持image资源的处理如下:

 
  
 
  
 
  
 
  

再次访问~/Home/Index,可以看到css中的image已经正常了:

clip_image006

到这里,缓存的实现可以说已经完成了,但总觉得还有个问题很纠结,那就是在修改cssjs之后,如何更新缓存?上面的代码中,可以修改web.config中的一个配置来改变version值,从而达到更新缓存的目的,但这是一个全局的配置,改变这个配置后,所有的cssjsurl都会跟着变。这意味着即使我们只改动其中一个css文件,所有的资源文件的缓存都失效了,因为url都变了。为了改进这一点,我们需要修改version的取值方式,让他不再读取web.config中的配置,而是以资源的最后修改时间作为version值,这样一旦某个资源文件的最后修改时间变了,该资源的缓存也就跟着失效了,但并不影响其他资源的缓存。修改UrlHelperExtensionsCache方法如下:

实现HTTP压缩

在文章的开头已经提到,DeflateStreamGZIPStream可以帮助我们实现Http压缩。让我们来看一下如何使用这两类。

首先要清楚的是我们要压缩的是文本内容,例如cssjs以及View(aspx),图片不需要压缩。

为了压缩cssjs,需要修改ResourceHandler类:

 
  
 
  
 
  
 
  
 
  

 

加粗的代码是修改的内容,并且只用了gzip压缩,并没有用deflate压缩,有兴趣的同学可以改一改。

为了压缩Viewaspx),我们需要添加一个ActionFilter,代码如下:

 
  
 
  
 
  
 
  

然后为HomeController添加这个Filter

 
  
 
  

这样就可以压缩View了。

最终的效果如下图:

第一次访问:

clip_image008

第二次访问:

clip_image010

转载于:https://www.cnblogs.com/default/archive/2012/06/03/2532635.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值