HttpContext, HttpModules 和 HttpHandlers

http://blog.csdn.net/quanke1981/archive/2007/06/13/1650419.aspx

httpApplication它本身对发送给应用程序的数据一无所知-它只是一个通过事件来通讯的消息对象.它触发事件并通过HttpContext对象来向被调用函数传递消息.实际的当前请求的状态数据由前面提到的HttpContext对象维护.它提供了所有请求专有的数据并从进入管道开始到结束一直跟随请求.图7显示了ASP.NET管道中的流程.注意上下文对象(即HttpContext),这个从请求开始到结束一直都是你”朋友”的对象,可以在一个事件处理函数中保存信息并在以后的事件处理函数中取出. 
   
    一旦管道被启动,HttpApplication开始象图六那样一个个的触发事件.每个事件处理器被触发,如果事件被挂接,这些处理器将执行它们自己的任务.这个处理的主要任务是最终调用挂接到此特定请求的HttpHandler.处理器(handler)是ASP.NET请求的核心处理机制,通常也是所有应用程序级别的代码被执行的地方.记住ASP.NET页面和Web服务框架都是作为HttpHandler实现,这里也是处理请求的的核心之处.模块(module)趋向于成为一个传递给处理器(handler)的上下文的预处理或后处理器.ASP.NET中典型的默认处理器包括预处理的认证,缓存以及后处理中各种不同的编码机制. 
   
    有很多关于HttpHandler和HttpModule的可用信息,所以为了保持这篇文章在一个合理的长度,我将提供一个关于处理器的概要介绍.

HttpModule 
   
    当请求在管道中传递时,HttpApplicaion对象中一系列的事件被触发.我们已经看到这些事件在Global.asax中作为事件被发布.这种方法是特定于应用程序的,可能并不总是你想要的.如果你要建立一个通用的可用被插入任何Web应用程序的HttpApplication事件钩子,你可用使用HttpModule,这是可复用的,不需要特定语应用程序代码的,只需要web.config中的一个条目. 
   
    模块本质上是过滤器(fliter)-功能上类似于ISAPI过滤器,但是它工作在ASP.NET请求级别上.模块允许为每个通过HttpApplication对象的请求挂接事件.这些模块作为外部程序集中的类存贮.,在web.config文件中被配置,在应用程序启动时被载入.通过实现特定的接口和方法,模块被挂接到HttpApplication事件链上.多个HttpModule可用被挂接在相同的事件上,事件处理的顺序取决于它们在Web.config中声明的顺序.下面是在Web.config中处理器定义. 
   
  <configuration> 
  <system.web> 
  <httpModules> 
  <add name= “BasicAuthModule” 
  type=”HttpHandlers.BasicAuth,WebStore” /> 
  </httpModules> 
  </system.web> 
  </configuration> 
   
    注意你需要指定完整的类型名和不带dll扩展名的程序集名. 
   
    模块允许你查看每个收到的Web请求并基于被触发的事件执行一个动作.模块在修改请求和响应数据方面做的非常优秀,可用为特定的程序提供自定义认证或者为发生在ASP.NET中的每个请求增加其他预处理/后处理功能.许多ASP.NET的功能,像认证和会话(Session)引擎都是作为HttpModule来实现的. 
   
    虽然HttpModule看上去很像ISAPI过滤器,它们都检查每个通过ASP.NET应用的请求,但是它们只检查映射到单个特定的ASP.NET应用或虚拟目录的请求,也就是只能检查映射到ASP.NET的请求.这样你可以检查所有ASPX页面或者其他任何映射到ASP.NET的扩展名.你不能检查标准的.HTM或者图片文件,除非你显式的映射这些扩展名到ASP.NET ISAPI dll上,就像图1中展示的那样.一个常见的此类应用可能是使用模块来过滤特定目录中的JPG图像内容并在最上层通过GDI+来绘制’样品’字样. 
   
    实现一个HTTP模块是非常简单的:你必须实现之包含两个函数(Init()和Dispose())的IHttpModule接口.传进来的事件参数中包含指向HTTPApplication对象的引用,这给了你访问HttpContext对象的能力.在这些方法上你可以挂接到HttpApplication事件上.例如,如果你想挂接AuthenticateRequest事件到一个模块上,你只需像列表5中展示的那样做 
   
    列表5:基础的HTTP模块是非常容易实现的 
   
  public class BasicAuthCustomModule : IHttpModule 
  { 
   public void Init(HttpApplication application) 
   { 
    // *** Hook up any HttpApplication events 
    application.AuthenticateRequest += new EventHandler(this.OnAuthenticateRequest); 
   } 
   public void Dispose() { } 
   
   public void OnAuthenticateRequest(object source, EventArgs eventArgs) 
   { 
    HttpApplication app = (HttpApplication) source; 
    HttpContext Context = HttpContext.Current; 
    … do what you have to do… } 
   } 
   
    记住你的模块访问了HttpContext对象,从这里可以访问到其他ASP.NET管道中固有的对象,如请求(Request)和响应(Response),这样你还可以接收用户输入的信息等等.但是记住有些东西可能是不能访问的,它们只有在处理链的后段才能被访问. 
   
    你可以在Init()方法中挂接多个事件,这样你可以在一个模块中实现多个不同的功能.然而,将不同的逻辑分到单独的类中可能会更清楚的将模块进行模块化(译注:这里的模块化和前面的模块没有什么关系)在很多情况下你实现的功能可能需要你挂接多个事件-例如一个日志过滤器可能在BeginRequest事件中记录请求开始时间,然后在EndRequest事件中将请求结束写入到日志中. 
   
    注意一个HttoModule和HttpApplication事件中的重点:Response.End()或HttpApplication.CompleteRequest()会在HttpApplication和Module的事件链中”抄近道”.看”注意Response.End()”来获得更多信息. 
   
    注意Response.End() 
   
    当创建HttpModule或者在Global.asax中实现事件钩子的时候,当你调用Response.End或 Appplication.CompleteRequest的时候要特别注意.这两个函数都结束当前请求并停止触发在HTTP管道中后续的事件,然后发生将控制返回到Web服务器中.当你在处理链的后面有诸如记录日志或对内容进行操作的行为时,因为他们没有被触发,有可能使你上当.例如,sample中logging的例子就会失败,因为如果调用Response.End()的话,EndRequest事件并不会被触发

 

==============================================

关于HttpHandlers和HttpModules的不同

http://www.cnblogs.com/ricksun/articles/1545491.html

当 IIS 接收一个请求时,根据 IIS 的设置将扩展映射到一个 ISAPI 筛选器。将 .ASPX、.asmx、.asd 和其他扩展映射到 ASPnet_isapi.dll,该 ASPnet_isapi.dll 只是一种启动 ASP.NET 运行库的 ISAPI 筛选器。一旦请求到达 ASP.NET 运行库,它在 HTTPApplication 对象处启动,该对象担当 ASP.NET Web 应用程序的宿主。HTTPApplication 对象:
1.
读取机器级和应用程序级的配置文件。
2.
通过一个或多个 HTTPModule 实例传递请求。每个 HTTPModule 提供一种服务,例如会话维护、身份验证,或配置文件维护。这些模块将请求传递回 HTTPApplication。
3.
根据谓词和路径将请求传递给 HTTPHandler。谓词指请求中使用的 HTTP 谓词(GET、POST、FTP,等等),而路径指应用程序中的 URL。根据处理程序的配置方式,该请求可能作为一个 ASP.NET 页(System.Web.UI.Page 为 IHTTPHandler 的一种实现)加以处理,或者该请求可能触发另一个操作,例如批编译所有的 Web 页(precomiplation.asd 触发 PrecompHandler)。
在 ASP.NET 2.0 中,该模型没有变化,但是,添加了几种新模块和处理程序以提供其他的服务。与 ASP.NET 1.x 一样,您可以扩展、替换或重新配置任何模块或处理程序类,以提供自己的自定义功能。
从这里可以看到,
httpModules只从功能性方面出发来触发事件.
而httpHandler从访问方式及访问文件后缀来触发事件.
  

 

ASP.Net处理Http Request时,使用Pipeline(管道)方式,由各个HttpModule对请求进行处理,然后到达 HttpHandler,HttpHandler处理完之后,仍经过Pipeline中各个HttpModule的处理,最后将HTML发送到客户端浏览 器中。

生命周期中涉及到几个非常重要的对象:HttpHandler,HttpModule,IHttpHandlerFactory,他们的执行(顺序)大致的执行过程是这样的:client端发送页面请求,被IIS的某个进程截获,它根据申请的页 面后缀(.aspx)不同,调用不同的页面处理程序(.asp->asp.dll; .aspx->ISAPI.dll).而页面处理程序在处理过程中,则要经历HttpModule,HttpHandler的处理:前者HttpModule用于页面处理前和处理后的一些事件的处理后者HttpHandler进行真正的页面的处理
如前所说,HttpModule会在页面处理前和后对页面进行处理,所以它不会影响真正的页面请求。通常用在给每个页面的头部或者尾部添加一些信息(如版 权声明)等.曾经见过一些免费的空间,我们的页面上传上去后,浏览的时候发现,在每个页面的头部和尾部多了很多小广告….,如果理解了 HttpModule的原理,要做这个就不是很难了~

IHttpModule与IHttpHandler的区别整理
1.先后次序.先IHttpModule,后IHttpHandler. 注:Module要看你响应了哪个事件,一些事件是在Handler之前运行的,一些是在Handler之后运行的
2.对请求的处理上:
   IHttpModule是属于大小通吃类型,无论客户端请求的是什么文件,都会调用到它;例如aspx,rar,html的请求.
   IHttpHandler则属于挑食类型,只有ASP.net注册过的文件类型(例如aspx,asmx等等)才会轮到调用它.
3.IHttpHandler按照你的请求 生成响应的内容,IHttpModule对请求进行预处理,如验证、修改、过滤等等,同时也可以对响应进行处理

 

ASP.Net系统本身配置有很多HttpHandler和HttpModule,以处理aspx等.Net标准的页面文件,以及这些页面文件中标 准的事件处理等。查看%System%/Microsoft.NET\Framework\v2.0.50727\CONFIG目录下的 web.config文件中的httpHandlers和httpModules节点,可以看到这些配置。如果有兴趣,可以使用Reflector查 看.Net系统中相关的类和方法,了解.Net如何处理以及做了什么处理。

.Net也提供了一套机制来开发自定义的HttpHandler和 HttpModule,均可以用于对HttpRequest的截取,完成自定义的处理。 HttpModule 继承System.Web.IHttpModule接口,实现自己的HttpModule类。必须要实现接口的两个方法:Init和Dispose。在 Init中,可以添加需要截取的事件;Dispose用于资源的释放,如果在Init中创建了自己的资源对象,请在Dispose中进行释放。


 1namespace MyModule
 2{
 3 public class MyHttpModule : IHttpModule
 4 {
 5    public MyHttpModule()
 6    {
 7    }

 8  
 9    //Init方法用来注册HttpApplication 事件。
10     public void Init(HttpApplication r_objApplication)
11    {
12      r_objApplication.BeginRequest += new EventHandler(this.BeginRequest);
13    }
    
14
15    public void Dispose()
16    {
17    }
    
18
19    private void BeginRequest(object r_objSender, EventArgs r_objEventArgs)
20    {
21      HttpApplication objApp = (HttpApplication)r_objSender;
22      objApp.Response.Write(您请求的URL为 + objApp.Request.Path);
23    }

24 }

25}
   
26

将编译的dll文件拷贝到web项目的bin目录下,在web项目的web.config文件system.web节点中配置: 
    这样就将自定义的HttpModule类MyHttpModule插入到了当前web的HttpModule的Pipeline中。 HttpModule主要功能是Application的各个事件进行截取,在这些事件中完成自己的处理。其实如果自己开发一些项目,直接在 Global.asax中处理已经足够了。如果是开发一个Framework或者是某些方面的组件,需要在事件中添加处理,开发自定义的 HttpModule,可以避免使用Framework或者组件时,还得手工在Global.asax中添加代码。     目前想到的开发自定义HttpModule的用途,有全局的身份/权限验证、自定义网站访问/操作日志的记录、处于管理/调试等目的对站点进行监控追踪 等。当然,如果是结合自定义的HttpHandler进行Framework的开发,HttpModule可以用于其它的一些特殊的处理。

      <httpModules>
         <add name=”test” type=”MyHttpModuleTest.MyHttpModule,MyHttpModule”/>
       </httpModules>
   注意要区分大小写,因为web.config作为一个XML文件是大小写敏感的。“type=MyHttpModuleTest.MyHttpModule,MyHttpModule”告诉我们系统将会将http request请求交给位于MyHttpModule.dll文件中的MyHttpModuleTest.MyHttpModule类去处理。HttpHandler是完全的对Http Request的截取。
    首先,继承System.Web.IHttpHandler接口,实现自己的HttpHandler类。必须要实现接口的ProcessRequest方 法和IsReusable属性。ProcessRequest方法中完成对每个Http Request的处理,发送处理结果的HTML到输出缓存中。IsReusable属性被.Net Framework调用,用以确定这个HttpHandler的实例是否可以被重用于同类型其它的Request处理。
    如果你在自己的HttpHandler类中,需要读取或者是写Session值,需要再继承一个接口IRequiresSessionState。这个接 口没有任何方法,只是一个标记接口。继承这个接口之后,就可以在自己的HttpHandler中访问Session,可以在Session中写入值。


 1namespace MyHandler
 2{
 3  public class MyHttpHandler : IHttpHandler, IRequiresSessionState
 4  {
 5    public MyHttpHandler() {}
 6    public bool IsReusable
 7    {
 8      get return true; }
 9    }

10    public void ProcessRequest(HttpContext context)
11    {
12      HttpResponse objResponse = context.Response ;
13      objResponse.Write(This request is handled by MyHttpHandler);
14    }

15  }

16}

17
18

把编译的dll文件拷贝到web项目的bin目录下。
    接下来,这样来测试一下MyHttpHandler。我们为IIS配置一个以.cc为后缀名的文件类型,用我们写的MyHttpHandler来处理。
    首先,在IIS站点的Configuration配置里面,添加一个对.cc后缀名处理的Application Extention Mapping项。   
    然后,在web项目的web.config节点节点中配置:

MyHttpHandler, MyHandler”/>

    verb属性配置这个HttpHandler处理那些HTTP方法,例如GET、POST等,如果是处理所有方法,就用*。path属性配置HttpHandler对哪些文件进行处理,例如可以是myfile.cc,如果是处理所有的.cc文件,就用*.cc。
    这样,这个站点上所有.cc类型文件的访问,都由MyHttpHandler处理。使用http://localhost/站点虚拟目录/a.cc访问测试站点,可以看到测试效果。当然,a.cc这个文件在Web服务器上是并不存在的。

    对HttpHandler的使用,比较典型的有.Net的Web MVC开源项目Maverick。Maverick使用一个Dispatcher类对所有的Http Request进行截取,他以.m作为后缀名向Web服务器提交请求,在Dispatcher中,将.m的后缀去掉,提取Command Name,然后以这个command name从配置文件中加载处理的flow,形成一个chain,依次对chain上的各个command和view进行处理,对各个command和 view的处理结果可能会在chain中选择不同的处理分支,每个处理的Step中将处理结果的HTML写入Response的缓存中进行输出。
    总体来说,Maverick的框架架构概念很不错,但也存在明显的缺陷,以后有时间再详细的写写它的架构和需要改进之处。

    总之,将HttpModule、HttpHandler,以及使用Ajax等将客户端进行封装结合起来,能够给web项目的开发带来非常大的改善空间。

Asp.Net HttpHandler实现URL重写的
我们经常看到很多网站访问文章的时候才用的是***.html 或***.shtml (如本blog的日志访问效果),其时这写文件在服务器上不存在的,那为什么会出现这样的效果呢,是因为Web服务器上对URL执行了重写,把访问的 URL根据特定的格式重写成内部访问页面来实现的,它的好处是便于用户理解,同时搜索引擎也能更好地收入你的网站,当然其它的好处也很多,这里不做一一介 绍了。 
本文所讲的是使用Asp.Net中的HttpHandler实现URL重写的,它所实现的原理请看这里,本程序可以处理任何Url,因为我在程序中使用了URL过虑,只有访问文件名是数字的才进行处理,并指在内部执行一个新的页面,并输出数据,代码如下:


 1public void ProcessRequest(HttpContext Context)
 2{    
 3try 
 4{        
 5    //申明Request         
 6    HttpRequest Request = Context.Request; 
 7    //取来路Url的绝对路径        
 8    string Url = Request.Url.AbsolutePath; 
 9    //取访问的Web文件的开始字符间隔数
10    int RegStart = Url.LastIndexOf(/+ 1
11    //申明一个确定Web文件名是否全是数字
12    Regex Reg = new Regex(@”\d+); 
13    //用正则表达式进行匹配 
14    if (Reg.IsMatch(Url, RegStart)) 
15    
16    //如果web文件名是数字,则判定是查询相关文章,执行指定页面 
17    Context.Server.Execute(~/PermaLink.aspx?id= + Reg.Match(Url, RegStart).Value);        
18}
    
19}

20catch
21{
22     Context.Response.Redirect(Context.Request.Url.ToString()); 
23}

24}

25

当然你首先要做的是先建一个类,并继承自IHttpHandler,然后把这段代码拷入,并编译。在Web项目中若要使用此功能,需要在web.config里面加上如下语句:
<httpHandlers>
    <add verb=”*” path=”*.shtml” type=”HttpHandle.UrlRewrite” />
</httpHandlers>
同时,还要在IIS中对Web项目进行配置,在Web项目的属性中,在主目录选项卡里,把执行权限改为”脚本和可执行文件”,然后打开配置,在应用程序扩展里加上需重写的文件格式的扩展,好了,成事具备,只欠运行了。

 

httpHandlers和httpModules接口介绍

http://news.ccidnet.com/art/32855/20100723/2126553_3.html

Tags: