httpHandlers是什么?httpModules又是什么?原来我都不知道,只得先搞清楚这两样,再来研究blogengine了。
Two Interceptors:HttpModule and HttpHandlers 这是我在codeproject上搜到的标题,翻译过来是两个拦截器:HttpModule 与 HttpHandlers
拦截器?拦截神马?要他作甚?
诞生背景
很多时候我们会有一些需求,预处理什么的得在请求到达IIS上的源前面进行处理,例如运行一些安全机制处理,验证,URL重写,过滤等等操作,这个时候我们
不可能每个页面都去写,100个页面,我就要去写100次,那不疯了?此时HttpModule 与 HttpHandlers两兄弟就诞生了。
看看下面的图,更好理解。
HttpHandlers---基于扩展的预处理
1 <system.web>
2 <httpHandlers>
3 <add verb="*" path="*.GIF" type="MyPipeLine.clsMyHandler, MyPipeLine"/>
4 </httpHandlers>
5 </system.web>
verb:get或post,"*"表示对所有请求进行处理
path:文件扩展,上面就是只针对扩展为GIF的请求处理,也可以指明特定的文件,如A.GIF那么就只针对此文件处理了。
type:逗号前的字符串指明HttpHandler的实现类的类名,后面的字符串指明Dll文件的名称。
下图中,如果来的请求是扩展为GIF的那么就是Handler 3处理。
HttpModules---基于事件的预处理
1 <httpModules>
2 <add name="clsMyModule" type="MyPipeLine.clsMyModule, MyPipeLine"/>
3 </httpModules>
其中type属性为HttpModule的标识号和类库名称,name属性则为该模块取一个较为友好的名称方便 在Global.asax调用
从下图中可以看到,在handler前后都有响应事件
图中事件不全,看下面列表
- BeginRequest:请求已开始。如果您需要在请求刚开始时执行某些操作(例如在每页的顶部显示广告横幅),请同步此事件。
- AuthenticateRequest:如果您要插入自己自定义的身份验证方案(例如,在数据库中查找用户以验证密码),请构建一个模块以同步此事件并按您需要的方式验证用户身份。
- AuthorizeRequest:此事件用于内部实现授权机制(例如,将您的访问控制列表 (ACL) 存储在数据库中而不是文件系统中)。虽然您可以覆盖此事件,但是最好不要这样做。
- ResolveRequestCache:此事件确定是否可以从输出缓存中调用某个页面。如果您要编写自己的缓存模块(例如,构建基于文件的缓存,而不是内存缓存),请同步此事件以确定是否从缓存中调用页面。
- AcquireRequestState:从状态存储中检索会话状态。如果您要构建自己的状态管理模块,请同步此事件以从您的状态存储中抓取会话状态。
- PreRequestHandlerExecute:此事件在执行 HTTP 处理程序之前发生。
- PostRequestHandlerExecute:此事件在执行 HTTP 处理程序之后发生。
- ReleaseRequestState:将会话状态重新存储在状态存储中。如果您要构建一个自定义会话状态模块,则必须将您的状态重新存储在状态存储中。
- UpdateRequestCache:此事件将输出重新写入输出缓存。如果您要构建自定义缓存模块,则可以将输出重新写入缓存中。
- EndRequest:请求已完成。您可能希望构建一个调试模块,以便将整个请求的信息收集到一起,然后将信息写入页面中。
对于每个请求传输,模块都可以与下列事件同步。这些事件的顺序不是固定的。- PreSendRequestHeaders:此事件在发送标头之前发生。如果您要添加其他标头,则可以通过自定义模块同步此事件。
- PreSendRequestContent:此事件在调用 Response.Flush 方法时发生。如果您要添加其他内容,则可以通过自定义模块同步此事件。
- Error:此事件在出现未处理的异常时发生。如果您要编写自定义的错误处理程序,请同步此事件。
我们可以用httpmodule注册上面这些事件,当有请求的时候,被注册的事件就会执行了。
引用来的结论
“Modules are called before and after the handler executes. Modules enable developers to intercept, participate in, or modify each individual request. Handlers are used to process individual endpoint requests. Handlers enable the ASP.NET Framework to process individual HTTP URLs or groups of URL extensions within an application. Unlike modules, only one handler is used to process a request”.
理了半天头绪,貌似有点懂了的样子,那么就看看blogengine吧。
1 <httpModules>
2 <add name="WwwSubDomainModule" type="BlogEngine.Core.Web.HttpModules.WwwSubDomainModule, BlogEngine.Core"/>
3 <add name="UrlRewrite" type="BlogEngine.Core.Web.HttpModules.UrlRewrite, BlogEngine.Core"/>
4 <add name="CompressionModule" type="BlogEngine.Core.Web.HttpModules.CompressionModule, BlogEngine.Core"/>
5 <add name="ReferrerModule" type="BlogEngine.Core.Web.HttpModules.ReferrerModule, BlogEngine.Core"/>
6 <add name="SecurityModule" type="BlogEngine.Core.Security, BlogEngine.Core"/>
7 <add name="RightModule" type="BlogEngine.Core.Right, BlogEngine.Core"/>
8 <!--Remove the default ASP.NET modules we don't need-->
9 <remove name="PassportAuthentication"/>
10 <remove name="Profile"/>
11 <remove name="AnonymousIdentification"/>
12 </httpModules>
上面这一系列的处理干什么的呢?当然他们是按顺序执行的。
从一大大http://www.cnblogs.com/Thriving-Country/archive/2008/11/13/1332659.html那挖过来现成的,特此标注
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
1 public override void Write(byte[] buffer, int offset, int count)
2 {
3 var html = Encoding.UTF8.GetString(buffer);
4
5 var regex =
6 new Regex(
7 "<script\\s*src=\"((?=[^\"]*webresource.axd)[^\"]*)\"\\s*type=\"text/javascript\"[^>]*>[^<]*(?:</script>)?",
8 RegexOptions.IgnoreCase);
9 html = regex.Replace(html, new MatchEvaluator(this.Evaluator));
10
11 var outdata = Encoding.UTF8.GetBytes(html);
12 this.sink.Write(outdata, 0, outdata.GetLength(0));
13 }
SecurityModule:提供统一的验证和授权处理
RightModule:用来提供权限信息的
httpHandlers
1 <httpHandlers>
2 <add verb="*" path="file.axd" type="BlogEngine.Core.Web.HttpHandlers.FileHandler, BlogEngine.Core" validate="false"/>
3 <add verb="*" path="image.axd" type="BlogEngine.Core.Web.HttpHandlers.ImageHandler, BlogEngine.Core" validate="false"/>
4 <add verb="*" path="syndication.axd" type="BlogEngine.Core.Web.HttpHandlers.SyndicationHandler, BlogEngine.Core" validate="false"/>
5 <add verb="*" path="sitemap.axd" type="BlogEngine.Core.Web.HttpHandlers.SiteMap, BlogEngine.Core" validate="false"/>
6 <add verb="*" path="trackback.axd" type="BlogEngine.Core.Web.HttpHandlers.TrackbackHandler, BlogEngine.Core" validate="false"/>
7 <add verb="*" path="pingback.axd" type="BlogEngine.Core.Web.HttpHandlers.PingbackHandler, BlogEngine.Core" validate="false"/>
8 <add verb="*" path="OpenSearch.axd" type="BlogEngine.Core.Web.HttpHandlers.OpenSearchHandler, BlogEngine.Core" validate="false"/>
9 <add verb="*" path="metaweblog.axd" type="BlogEngine.Core.API.MetaWeblog.MetaWeblogHandler, BlogEngine.Core" validate="false"/>
10 <add verb="*" path="rsd.axd" type="BlogEngine.Core.Web.HttpHandlers.RsdHandler, BlogEngine.Core" validate="false"/>
11 <add verb="*" path="css.axd" type="BlogEngine.Core.Web.HttpHandlers.CssHandler, BlogEngine.Core" validate="false"/>
12 <add verb="*" path="js.axd" type="BlogEngine.Core.Web.HttpHandlers.JavaScriptHandler, BlogEngine.Core" validate="false"/>
13 <add verb="*" path="res.axd" type="BlogEngine.Core.Web.HttpHandlers.ResourceHandler, BlogEngine.Core" validate="false"/>
14 <add verb="*" path="rating.axd" type="BlogEngine.Core.Web.HttpHandlers.RatingHandler, BlogEngine.Core" validate="false"/>
15 <add verb="*" path="opml.axd" type="BlogEngine.Core.Web.HttpHandlers.OpmlHandler, BlogEngine.Core" validate="false"/>
16 <add verb="*" path="blogml.axd" type="BlogEngine.Core.Web.HttpHandlers.BlogMLExportHandler, BlogEngine.Core" validate="false"/>
17 <add verb="*" path="sioc.axd" type="BlogEngine.Core.Web.HttpHandlers.Sioc, BlogEngine.Core" validate="false"/>
18 <add verb="*" path="apml.axd" type="BlogEngine.Core.Web.HttpHandlers.Apml, BlogEngine.Core" validate="false"/>
19 <add verb="*" path="foaf*.axd" type="BlogEngine.Core.Web.HttpHandlers.Foaf, BlogEngine.Core" validate="false"/>
20 <add verb="*" path="*.htm" type="System.Web.StaticFileHandler"/>
21 </httpHandlers>
一开始我看见***.axd,我也纳闷这些文件是什么,听说是httphandle处理的映像文件,不是实际存在的文件,其实还是很朦胧,原谅我的浅薄:-(
直到我看见
1 <script src="/BlogEngine.NET/js.axd?path=%2fBlogEngine.NET%2fScripts%2fjquery.js" type="text/javascript"></script>
2 <link rel="stylesheet" href="/BlogEngine.NET/themes/Standard/css.axd?name=/BlogEngine.NET/Styles/Global2.5.0.6.css" type="text/css">
3 <link href="http://localhost:52457/BlogEngine.NET/sioc.axd" title="SIOC" rel="meta" type="application/rdf+xml">
4 <link href="http://localhost:52457/BlogEngine.NET/apml.axd" title="APML" rel="meta" type="application/apml+xml">
5 <link href="http://localhost:52457/BlogEngine.NET/foaf.axd" title="FOAF" rel="meta" type="application/rdf+xml">
6 <link href="http://localhost:52457/BlogEngine.NET/syndication.axd?format=rss" title="Name of the blog (RSS)" rel="alternate" type="application/rss+xml">
7 <link href="http://localhost:52457/BlogEngine.NET/rsd.axd" title="RSD" rel="edituri" type="application/rsd+xml">
8 <link href="http://localhost:52457/BlogEngine.NET/opensearch.axd" title="Name of the blog" rel="search" type="application/opensearchdescription+xml">
9 <script src="http://localhost:52457/BlogEngine.NET/res.axd?lang=en-us" type="text/javascript"></script>
原来是这么个用法的,呵呵。
具体他们的作用是干什么的,再引用下,呵呵。
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两种格式,
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中的,或者给浏览器使用,或者给搜索引擎使用。