神秘的HttpHandler与HttpModule
大学时候我是从拖控件开始学习asp.net的,对.net的很多类库对象都不是很了解 。所以看到大家写一些个性的asp.net名词,就感觉asp.net总有一层神秘的面纱笼罩着,让我琢磨不透,相信园子里面也有很多和我经历差不多的.net攻城师 。在以前看HttpHandler与HttpModule都是神秘莫测的 。哈哈,今天我为大家展示下我对他的理解,以及应用 。
也许你不懂HttpHandler与HttpModule(大侠Return),也许你不知道HttpHandler与HttpModule的用途,也许你似懂非懂 。今天,请让我带领大家去领略一下HttpHandler与HttpModule的风采,今天我要让他变得So Easy !!
理解asp.net管线事件
何谓asp.net管线?简单的说就是页面的生命周期,就是页面从你开始请求到展现在你的浏览器期间,asp.net所做的一系列事件 。下面给你展现下这些事件(参见与Fish Li) 。
1. 对请求进行验证,将检查浏览器发送的信息,并确定其是否包含潜在恶意标记 。 有关更多信息,请参见 ValidateRequest 和脚本侵入概述 。
2. 如果已在 Web.config 文件的 UrlMappingsSection 节中配置了任何 URL,则执行 URL 映射 。
3. 引发 BeginRequest 事件 。
4. 引发 AuthenticateRequest 事件 。
5. 引发 PostAuthenticateRequest 事件 。
6. 引发 AuthorizeRequest 事件 。
7. 引发 PostAuthorizeRequest 事件 。
8. 引发 ResolveRequestCache 事件 。
9. 引发 PostResolveRequestCache 事件 。
10. 根据所请求资源的文件扩展名(在应用程序的配置文件中映射),选择实现 IHttpHandler 的类,对请求进行处理 。 如果该请求针对从 Page 类派生的对象
(页),并且需要对该页进行编译,则 ASP.NET 会在创建该页的实例之前对其进行编译 。
11. 引发 PostMapRequestHandler 事件 。
12. 引发 AcquireRequestState 事件 。
13. 引发 PostAcquireRequestState 事件 。
14. 引发 PreRequestHandlerExecute 事件 。
15. 为该请求调用合适的 IHttpHandler 类的 ProcessRequest 方法(或异步版 IHttpAsyncHandler.BeginProcessRequest) 。 例如,如果该请求针对某页,则
当前的页实例将处理该请求 。
16. 引发 PostRequestHandlerExecute 事件 。
17. 引发 ReleaseRequestState 事件 。
18. 引发 PostReleaseRequestState 事件 。
19. 如果定义了 Filter 属性,则执行响应筛选 。
20. 引发 UpdateRequestCache 事件 。
21. 引发 PostUpdateRequestCache 事件 。
22. 引发 EndRequest 事件 。
23. 引发 PreSendRequestHeaders 事件 。
24. 引发 PreSendRequestContent 事件 。
注意:
1.记着上面这些事件,不是瞎写的,他们的顺序更不是瞎写的 。是页面从开始请求到页面展现结束,他们是从一到二十四,从上到下,依次触发的 。
2.从BeginRequest开始的事件,并不是每个事件都会被触发,因为在整个处理过程中,随时可以调用Response.End() 或者有未处理的异常发生而提前结束整个过程 。所有事件中,只有EndRequest事件是肯定会触发的, (部分Module的)BeginRequest有可能也不会被触发 。
3.如果是IIS7,第10个事件也就是MapRequestHandler事件,而且在EndRequest 事件前,还增加了另二个事件:LogRequest 和 PostLogRequest 。只有当应用程序在 IIS 7.0 集成模式下运行,并且与 .NET Framework 3.0 或更高版本一起运行时,才会支持 MapRequestHandler、LogRequest 和 PostLogRequest 事件 。
总结:这些事件我们可以随意在你需要的事件中添加方法,类,属性等一些列属于你自己对请求的操作 。也就是说我们以前都是在页面级编程,现在,我们可以在请求级处理项目,处理请求 。具体怎么做,要看下面的HttpMoudle和HttpHandler的神奇功效了 。
理解HttpHandler与HttpModule
先说HttpHandler 。
首先你应该明白asp.net是怎么处理我们的请求文件的,这里不扯与asp.net无足轻重的看似更加底层的神秘面纱,那么.net是怎么处理我们的请求文件的呢?给你看个东西 。
打开你电脑上C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\ 目录下的web.config 文件 。找到httpHandlers节点,看他下面都写了什么 。你不想打开的话看我的 。
复制代码 代码如下:
View Code
<httpHandlers>
<add verb="*" path="*.rules" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add verb="*" path="*.xoml" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="false"/>
<add path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="false"/>
<add path="trace.axd" verb="*" type="System.Web.Handlers.TraceHandler" validate="True"/>
<add path="WebResource.axd" verb="GET" type="System.Web.Handlers.AssemblyResourceLoader" validate="True"/>
<add path="*.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True"/>
<add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True"/>
<add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True"/>
<add path="*.asmx" verb="*" type="System.Web.Services.Protocols.WebServiceHandlerFactory, System.Web.Services, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" validate="False"/>
<add path="*.rem" verb="*" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="False"/>
<add path="*.soap" verb="*" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="False"/>
<add path="*.asax" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.ascx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.master" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.skin" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.browser" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.sitemap" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.dll.config" verb="GET,HEAD" type="System.Web.StaticFileHandler" validate="True"/>
<add path="*.exe.config" verb="GET,HEAD" type="System.Web.StaticFileHandler" validate="True"/>
<add path="*.config" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.cs" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.csproj" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.vb" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.vbproj" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.webinfo" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.licx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.resx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.resources" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.mdb" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.vjsproj" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.java" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.jsl" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.ldb" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.ad" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.dd" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.ldd" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.sd" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.cd" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.adprototype" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.lddprototype" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.sdm" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.sdmDocument" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.mdf" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.ldf" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.exclude" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.refresh" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*" verb="GET,HEAD,POST" type="System.Web.DefaultHttpHandler" validate="True"/>
<add path="*" verb="*" type="System.Web.HttpMethodNotAllowedHandler" validate="True"/>
</httpHandlers>
上面这段代码是这样理解的:在<httpHandlers>结点中将不同的文件类型映射给不同的Handler去处理,对于.aspx来说,是由System.Web.UI.PageHandlerFactory来处理 。而对于.cs来说,是由System.Web.HttpForbiddenHandler 处理....
上面的是默认Handler处理,当然知道了HttpHandler之后,我们也可以自己注册自己的HttpHandler,写自己的HttpHandler处理程序,处理不同类型的文件,这个等会儿我实现下,给大家看看 。
问题: 既然HttpHandler的作用是将请求中,各个不同类型后缀名的文件,映射给不同的处理程序去处理,那么处理程序是在页面生命周期中的那个时间中映射处理请求的呢?
答: 依照上面的24个事件,这个HttpHandler节点中的映射是在第10个步骤中触发的 。而他映射给不同的处理程序,这些处理程序中方法、类的实现是在第15步触发的 。
再说HttpModule 。
HttpHandler是针对一类型的文件,映射给指定的处理程序对请求进行出来 。并且映射,与处理都发生在asp.net已经指定好的事件中 。
而HttpModule则是针对所有的请求文件,映射给指定的处理程序对请求进行处理,而这些处理,可以发生在请求管线中的任何一个事件中 。也就是说你订阅哪个事件,这写处理就发生于那个事件中,处理过后再执行,你订阅过的事件的下一个事件,当然你也可以终止所有事件直接运行最后一个事件,这就意味这他可以不给HttpHandler机会,很牛的HttpModule 。
HttpHandler的使用
HttpHandler的使用通过一种防盗链技术来演示
1.首先注册HttpHandler:在Web.config中注册
复制代码 代码如下:
<httpHandlers>
<!--映射jpg格式的文件,给ProcessHandler_test.CustomHandler处理 。-->
<!--type里面逗号之前 命名空间加类名(ProcessHandler_test.CustomHandler),后面程序集名称-->
<add path="*.jpg" verb="*" type="httphander_test.CustomHandler, ProcessHandler_test" />
</httpHandlers>
上面注册是把网站中请求jpg格式文件的请求,映射给命名空间为httphander_test类名为CustomHandler的程序集ProcessHandler_test来处理请求 。
2.如果想通过HttpHandler处理请求,必须在映射的处理程序中实现接口IHttpHandler
3.映射到的程序代码如下
复制代码 代码如下:
View Code
namespace httphander_test
{
public class CustomHandler :IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// 获取文件服务器端物理路径
string FileName = context.Server.MapPath(context.Request.FilePath);
// 如果UrlReferrer为空,则显示一张默认的禁止盗链的图片
if (context.Request.UrlReferrer.Host == null)
{
context.Response.ContentType = "image/gif";
context.Response.WriteFile("/error.gif");
}
else
{
// 如果 UrlReferrer中不包含自己站点主机域名,则显示一张默认的禁止盗链的图片
if (context.Request.UrlReferrer.Host.IndexOf("yourdomain.com") > 0)
{
context.Response.ContentType = "image/gif";
context.Response.WriteFile(FileName);
}
else
{
context.Response.ContentType = "image/gif";
context.Response.WriteFile("/error.gif");
}
}
}
public bool IsReusable
{
get { throw new NotImplementedException(); }
}
}
}
按 Ctrl+C 复制代码 上面这个简单的实例就完成了,如果有Jpg格式文件的请求,而不是在本网站的域名中请求,那么就会输出一个指定的错误图片来替换原连接图片 。
总结:httpHandler的功能远不止这些,希望你能理解他是对一类文件请求的处理,也希望你能理解他在请求管道中的事件位置,这样对您理解会更有帮助 。
HttpModule的使用
由于HttpModule过于强大的功能,也就是说任何一个请求都要经过注册过的HttpModule处理程序,所以大家在用他的时候一定要对各种请求做好判断,也就是处理什么请求,就让这个请求走那个处理程序,不要让他每个方法,都去执行 。要不会让程序负重,得不偿失 。
使用HttpModule跟HttpHandler的步骤类似,而HttpModule实现的是IHttpModule接口 。
在这里,他的具体案例,我就不写了,我以前写过一个Url重写的案例,就是使用的它,大家可以看看 。链接为: url重写