BlogEngine.Net架构与源代码分析系列part13:实现分析(上)——HttpHandlers与HttpModules...

     这已经是系列的第13篇了,实际上到现在为止您应该对BlogEngine.Net的整体设计有了一定的把握,对部分实现细节有了比较深刻的认识,在阅读BlogEngine.Net时希望坚持到最后,并把握住宏观,深入到微观。本文将详细介绍BlogEngine.Net中的HttpHandlers与HttpModules,主要说明它们要实现的功能以及如何使用,并对几个必要的HttpHandler或HttpModule进行比较细致的分析。

     HttpHandler和HttpModule

     对于HttpHandler和HttpModule我这里不想多说了,因为关于它们讲解的文章实在太多太多了,大家可以在博客园的找找看中直接输入“HttpHandler和HttpModule”就可以找到。我的理解就是一个HttpHandler要实现IHttpHandler接口,主要是对某个请求进行直接处理,一个HttpModule要实现IHttpModule接口,主要是在HttpApplication的生命周期的事件中对请求和响应进行过滤。它们都可以在Web.config文件中进行配置。

     BlogEngine.Net中的HttpHandler

     BlogEngine.Net中的HttpHandler都在BlogEngine.Core.Web.HttpHandlers空间下(除了MetaWeblogHandler,已经讲过,这里就不包含它了),通过Web.config我们可以看到它们的映射关系:

ContractedBlock.gif ExpandedBlockStart.gif HttpHandlers映射表
<httpHandlers>
    
<add verb="*" path="file.axd" type="BlogEngine.Core.Web.HttpHandlers.FileHandler, BlogEngine.Core" validate="false"/>
    
<add verb="*" path="image.axd" type="BlogEngine.Core.Web.HttpHandlers.ImageHandler, BlogEngine.Core" validate="false"/>
    
<add verb="*" path="syndication.axd" type="BlogEngine.Core.Web.HttpHandlers.SyndicationHandler, BlogEngine.Core" validate="false"/>
    
<add verb="*" path="sitemap.axd" type="BlogEngine.Core.Web.HttpHandlers.SiteMap, BlogEngine.Core" validate="false"/>
    
<add verb="*" path="trackback.axd" type="BlogEngine.Core.Web.HttpHandlers.TrackbackHandler, BlogEngine.Core" validate="false"/>
    
<add verb="*" path="pingback.axd" type="BlogEngine.Core.Web.HttpHandlers.PingbackHandler, BlogEngine.Core" validate="false"/>
    
<add verb="*" path="opensearch.axd" type="BlogEngine.Core.Web.HttpHandlers.OpenSearchHandler, BlogEngine.Core" validate="false"/>
    
<add verb="*" path="metaweblog.axd" type="BlogEngine.Core.API.MetaWeblog.MetaWeblogHandler, BlogEngine.Core" validate="false"/>
    
<add verb="*" path="rsd.axd" type="BlogEngine.Core.Web.HttpHandlers.RsdHandler, BlogEngine.Core" validate="false"/>
    
<add verb="*" path="css.axd" type="BlogEngine.Core.Web.HttpHandlers.CssHandler, BlogEngine.Core" validate="false"/>
    
<add verb="*" path="js.axd" type="BlogEngine.Core.Web.HttpHandlers.JavaScriptHandler, BlogEngine.Core" validate="false"/>
    
<add verb="*" path="rating.axd" type="BlogEngine.Core.Web.HttpHandlers.RatingHandler, BlogEngine.Core" validate="false"/>
    
<add verb="*" path="opml.axd" type="BlogEngine.Core.Web.HttpHandlers.OpmlHandler, BlogEngine.Core" validate="false"/>
    
<add verb="*" path="blogml.axd" type="BlogEngine.Core.Web.HttpHandlers.BlogMLExportHandler, BlogEngine.Core" validate="false"/>
    
<add verb="*" path="sioc.axd" type="BlogEngine.Core.Web.HttpHandlers.Sioc, BlogEngine.Core" validate="false"/>
    
<add verb="*" path="apml.axd" type="BlogEngine.Core.Web.HttpHandlers.Apml, BlogEngine.Core" validate="false"/>
    
<add verb="*" path="foaf*.axd" type="BlogEngine.Core.Web.HttpHandlers.Foaf, BlogEngine.Core" validate="false"/>
</httpHandlers>

下面对它们进行一一描述:

FileHandler:主要完成对于一些物理文件的请求,例如在文章中插入的文件资源的请求就由它来处理。它的实现比较简单,就直接去磁盘的文件保存目录中读取,我们只要留意一下SetContentType就行了。

ImageHandler:与FileHandler类似,不过它处理的是图片。与FileHandler分开的原因主要就是图片需要在页面上展现(ContentType必须给浏览器讲清楚或采用默认)。

SyndicationHandler:它比较复杂,主要完成各种订阅需求的处理,需要结合SyndicationFormat(格式枚举)和SyndicationGenerator(按照SyndicationFormat的格式生成XML)一起使用。我们可以看一下它的实现过程,首先根据请求的查询字符串生成标题,格式,列表(GenerateItemList使用了Search等),使用CleanList进行了一个过滤,分页处理,SetHeader,最后使用SyndicationGenerator的WriteFeed进行了输出。这里考虑的情况比较多,但是BlogEngine.Net使用的分割方法很好的解决了复杂的订阅问题,值得研究一下。

SiteMap:网站地图,可以给一些搜索引擎提供更好的搜索信息,以XML格式将一些文章等页面的链接输出。

TrackbackHandler:接收Trackback信息的处理,前文已经讲过,这里不多说了。

PingbackHandler:接收Pingback信息的处理,前文已经讲过,这里也不多说了。

OpenSearchHandler:提供公开搜索处理,前文已经讲过,这里也不多说了。

RsdHandler:这个处理器很有用,它完成将BlogEngine.Net中的一些公开的接口等信息发布出去,类似WebService的WSDL文件。

CssHandler:主要处理了页面中的Css文件的压缩,上文中讲述BlogBasePage中提及过。处理器的实现很值得关注,压缩可以使用gzip或deflate两种格式,

ContractedBlock.gif ExpandedBlockStart.gif 经典的压缩处理
 1private const string GZIP = "gzip";
 2private const string DEFLATE = "deflate";
 3
 4private static void Compress(HttpContext context)
 5ExpandedBlockStart.gifContractedBlock.gif{
 6    if (context.Request.UserAgent != null && context.Request.UserAgent.Contains("MSIE 6"))
 7        return;
 8
 9    if (IsEncodingAccepted(GZIP))
10ExpandedSubBlockStart.gifContractedSubBlock.gif    {
11        context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress);
12        SetEncoding(GZIP);
13    }

14    else if (IsEncodingAccepted(DEFLATE))
15ExpandedSubBlockStart.gifContractedSubBlock.gif    {
16        context.Response.Filter = new DeflateStream(context.Response.Filter, CompressionMode.Compress);
17        SetEncoding(DEFLATE);
18    }

19}

并提供了一些事件供外界Hookup处理。压缩之前去掉空格等字符,分为从本地获得文件和从远程使用WebClient下载文件。并使用了缓存。

JavaScriptHandler:主要处理页面中引用的脚本的压缩,与Css处理方式类似。注意StripWhitespace的处理与Css的不同。

RatingHandler:主要完成给Post打分的功能,记得上文中有部分涉及到,从PostViewBase中的Rating可以看出,这个请求实际上是通过Ajax发送过来的。

OpmlHandler:获得OPML列表文件,类似收藏文章的列表。

BlogMLExportHandler:BlogEngine.Net中的文章导出处理,以前的文章讲过。

Sioc、Foaf、Apml的注释都是“Based on John Dyer's (http://johndyer.name/) extension.”,这个应该是对于某个标准XML的输出吧,主要提供了本博客系统中的一些公开的信息。关于它们不做太多的研究,我想这并不影响我们对BlogEngine.Net的研究。

     实际上这些HttpHandlers的请求链接很多都是在BlogBasePage加入到Html的Head中的,或者给浏览器使用,或者给搜索引擎使用。

     BlogEngine.Net中的HttpModule

     BlogEngine.Net中的HttpModule都在BlogEngine.Core.Web.HttpModules空间下,通过Web.config我们可以看到它们的映射关系:

ContractedBlock.gif ExpandedBlockStart.gif httpModules映射表
<httpModules>
    
<add name="WwwSubDomainModule" type="BlogEngine.Core.Web.HttpModules.WwwSubDomainModule, BlogEngine.Core"/>
    
<add name="UrlRewrite" type="BlogEngine.Core.Web.HttpModules.UrlRewrite, BlogEngine.Core"/>
    
<add name="CompressionModule" type="BlogEngine.Core.Web.HttpModules.CompressionModule, BlogEngine.Core"/>
    
<add name="ReferrerModule" type="BlogEngine.Core.Web.HttpModules.ReferrerModule, BlogEngine.Core"/>
    
<!--Remove the default ASP.NET modules we don't need-->
    
<remove name="PassportAuthentication"/>
    
<remove name="Profile"/>
    
<remove name="AnonymousIdentification"/>
</httpModules>

请注意它们的注册顺序,因为WwwSubDomainModule和UrlRewrite都Hookup了HttpApplication的BeginRequest事件。下面对它们进行一一描述:

WwwSubDomainModule:Hookup了HttpApplication的BeginRequest事件,主要是对请求的URL中的"www"的处理以得到绝对的链接。

UrlRewrite:Hookup了HttpApplication的BeginRequest事件,对一些URL的重写,实际上WwwSubDomainModule和UrlRewrite都是在处理URL,我们在看BlogEngine.Net中的源代码时多留意一下它的URL,包括Post中的各种链接的URL等,注意区分它们都是做什么用的。

ReferrerModule:主要是对于请求的Referrer进行统计,纪录这些请求都是从哪里发送来的,提供了相应的事件供外部Hookup,注意IsSpam的实现和对于纪录日志使用了新线程来异步完成。

CompressionModule:一个Page页面的压缩处理模块,同样根据请求来判断是使用gzip还是deflate,对于页面中链接的WebResource也是用WebResourceFilter进行了过滤处理,WebResourceFilter实现了Stream,

ContractedBlock.gif ExpandedBlockStart.gif WebResourceFilter的Write方法
 1public override void Write(byte[] buffer, int offset, int count)
 2ExpandedBlockStart.gifContractedBlock.gif{
 3    byte[] data = new byte[count];
 4    Buffer.BlockCopy(buffer, offset, data, 0, count);
 5    string html = System.Text.Encoding.Default.GetString(buffer);
 6
 7    Regex regex = new Regex("<script\\s*src=\"((?=[^\"]*webresource.axd)[^\"]*)\"\\s*type=\"text/javascript\"[^>]*>[^<]*(?:</script>)?", RegexOptions.IgnoreCase);
 8    foreach (Match match in regex.Matches(html))
 9ExpandedSubBlockStart.gifContractedSubBlock.gif    {
10        string relative = match.Groups[1].Value;
11        string absolute = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority);
12        html = html.Replace(relative, Utils.RelativeWebRoot + "js.axd?path=" + HttpUtility.UrlEncode(absolute + relative));
13    }

14
15    byte[] outdata = System.Text.Encoding.Default.GetBytes(html);
16    _sink.Write(outdata, 0, outdata.GetLength(0));
17}

在重写的Write中主要是将webresource.axd转交给了JavaScriptHandler处理以达到压缩的目的。注意它是在PreRequestHandlerExecute中Hookup的,都是给Response提供的流过滤器。

     总结

     由于篇幅所限,对于BlogEngine.Net中一些HttpHandlers和HttpModules我并没有作更多的深入讨论,这里只是提供给大家一个学习指南,希望有所帮助。BlogEngine.Net中大量使用了正则匹配,Url处理,压缩,缓存等都是比较通用的,值得我们关注与学习。

     通用的处理方法值得我们去收藏

     上一篇:BlogEngine.Net架构与源代码分析系列part12:页面共同的基类——BlogBasePage

     下一篇:BlogEngine.Net架构与源代码分析系列part14:实现分析(下)——网站页面上值得参考的部分

     

     返回到目录

转载于:https://www.cnblogs.com/Thriving-Country/archive/2008/11/13/1332659.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值