关于HttpModule和HttpHandler以及HttpApplication
HttpRuntime打交道的是http协议跟IIS层面的东西,HttpApplication则具体到应用程序这一级别(也就是一个网站,这个跟web.config关系是基本一一对应的,像Module跟Handler的信息都是在这里定义),此时会生成相应的HttpContext(上下文信息,包括Request,Response等),在HttpApplication路由到具体的HttpHandler处理之时,HttpApplication的各个事件会被触发,而HttpModule则通过相应的事件如BeginRequest等来处理一些额外的事情,如UrlRewrite,缓存,安全验证等
管线(Pipeline)这个词也是很有点意思,这个词也形象地说明了每个Asp.net请求的处理过程: 请求是在一个管道中,要经过一系列的过程点,这些过程点连接起来也就形成一条线。 以上是我对于这个词的理解,如果有误,恳请给予指正。 这些一系列的过程点,其实就是由HttpApplication引发的一系列事件,通常可以由HttpModule来订阅, 也可以在Global.asax中订阅,这一系列的事件也就构成了一次请求的生命周期。
观察者模式:观察者模式定义了对象之间的一种联系,使得当一个对象改变状态时,其它对象会被相应的通知到。
Asp.net的管线设计正是采用了这种方式, 在这个设计模式中,观察者就是许多HttpModule对象,被观察的对象就是每一个请求,它的状态由HttpApplication控制,用于描述当前请求的处理阶段,
HttpApplication会根据一个特定的顺序修改这个状态,并在每个状态改变后引发相应的事件。 Asp.net会为每个请求分配一个HttpApplication对象来引发这些事件,因此可以让一大批观察者了解每个请求的状态, 每个观察者也可以在感兴趣的时候修改请求的一些数据。 这些与请求相关的数据的也就是HttpRequest, HttpResponse。
在处理该请求时将由 HttpApplication 类执行以下事件。 希望扩展 HttpApplication 类的开发人员尤其需要注意这些事件。 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.每个请求都将会映射到一个HttpHandler,通常也是处理请求的主要对象。
2.HttpModule可以任意订阅这些事件,在事件处理器中也可以参与修改请求的操作。
HttpHandler
HttpHandler通常是处理请求的核心对象。绝大多数的的请求都在【第10步】被映射到一个HttpHandler, 然后在【第15步】中执行处理过程,因此也常把这类对象称为处理器或者处理程序。我们熟知的Page就是一个处理器, 一个ashx文件也是一个处理器。
// 定义 ASP.NET 为使用自定义 HTTP 处理程序同步处理 HTTP Web 请求而实现的协定。 public interface IHttpHandler { // 获取一个值,该值指示其他请求是否可以使用 System.Web.IHttpHandler 实例。 // // 返回结果: // 如果 System.Web.IHttpHandler 实例可再次使用,则为 true;否则为 false。 bool IsReusable { get; } // 通过实现 System.Web.IHttpHandler 接口的自定义 HttpHandler 启用 HTTP Web 请求的处理。 void ProcessRequest(HttpContext context); }
我们可以采用以下方式在web.config中注册一个自定义的处理器:
<httpHandlers> <add path="/MyService.axd" verb="*" validate="false" type="MySimpleServiceFramework.MyServiceHandler"/> </httpHandlers>
HttpModule
前面我已经提到过HttpModule的工作方式:订阅管线事件,并在事件处理器中执行所需的相关操作。
这个描述看起来很平淡,但是,它的工作方式给了它无限强大的处理能力。
它的无限强大的处理能力来源于可以订阅管线事件,因此,它有能力可以在许多阶段修改请求, 这些修改最终可能会影响请求的处理。
前面我说过:“HttpHandler是处理请求的主要对象”,但HttpModule却可以随意指定将某个请求交给某个处理器来执行!
甚至,HttpModule也可以直接处理请求,完全不给HttpHandler工作的机会!
public interface IHttpModule { void Dispose(); void Init(HttpApplication app); }
在这二个方法中,第一个方法通常可以保持为空。最重要的方法就是Init,它给了HttpModule能订阅管线事件的机会, 然后在相应的事件处理中,我们就可以执行它的具体操作了。
<httpModules> <add name="DuplexGzipModule" type="MySimpleServiceFramework.DuplexGzipModule"/> </httpModules>
HttpModule的加载方式:ASP.NET会为每个请求分配一个HttpApplication对象,在每个HttpApplication对象的初始化操作中,它会加载所有在web.config中注册的HttpModule。由于Asp.net并不是只创建一个HttpApplication对象,而是多个HttpApplication对象, 因此每个HttpModule的Init事件是有可能被多次调用的。