HTTP处理流程图
当第一个请求到达时的动作如下图所示:
初始化所有核心应用程序对象之后,将通过创建 HttpApplication 类的实例启动应用程序。如果应用程序具有 Global.asax 文件,则 ASP.NET 会创建 Global.asax 类(从HttpApplication 类派生)的一个实例,并使用该派生类表示应用程序。
每次http请求都会有一个HttpApplication类型的对象来管理这次请求的过程。
为每次http请求创建一个HttpContext对象,此对象在整个Http处理过程中都是可访问的。
HttpApplication对象负责装配出整个“HTTP请求处理管线(HTTP Pipeline)”,这相当于一条加工流水线,让HttpContext对象在这条线上过一遍。
HttpContext对象经过流水线的不同部分时,HttpApplication对象会先后激发出一连串的事件。HTTP模块(HTTP Module)可以响应这些事件,在此事件响应代码中可以对HttpContext对象进行“加工和处理”。
HTTP模块可以看成是“生产流水线”中的工人。
HTTP模块对象是在HttpApplication对象的InitModules()方法中被创建的,创建时会调用其init方法,我们一般在HTTP模块对象Init()方法中书写代码对HttpApplication对象的事件进行注册。
在流水线的中部(处理完了相关的事件),HttpContext对象被最终的Page对象所接收(这就是为何可以在ASP.NET页面中通过Page类定义的Context属性访问HttpContext对象的原因)。
每个被访问的ASP.NET页面都会被转换为一个“派生自Page类的页面类”。
Page类实现了IHttpHandler接口,此接口定义了一个ProcessRequest()方法。
ASP.NET页面类生成以后被自动编译为程序集,然后其ProcessRequest()方法被自动调用。ProcessRequest()方法 的执行结果再次被HttpContext对象所承载,控制又转回到“HTTP请求处理流水线”中,HttpApplication对象继续激发后继的事 件。这时,如果还有特定的HTTP模块响应这些事件,则它们会被自动调用。
HttpContext对象带着最后的处理结果来到了“HTTP请求处理管线”的未端,其信息被取出来,再次以aspnet_isapi.dll为桥梁传送给工作者进程。工作者进程再将HTTP请求的处理结果转给HTTP.SYS,由它负责将结果返回给浏览器。
我们所写的那些页面代码,以及那一套复杂的页面生命周期,都是整个asp.net周期中的一部分,所有IhttpHandler的操作,都是在Application的PreRequestHandlerExecute事件和PostRequestHandlerExecute 事件之间完成的,IHttpHandler中的操作都是页面级别的操作,他们不能跨出页面这个范。
在应用程序级别的操作,应该使用IHttpModule。
要区分开HttpApplication和HttpApplicationState
HttpApplicationState是整个应用程序唯一的。
而HttpApplication则不是唯一的。
你在页面中写的Application[“key”] = “”value; 这个Application其实是HttpApplicationState
每一次请求都由一个HttpApplication对象来处理,在处理过程中,这个对象不能再处理其他请求,并发访问时,会为不同访问分配不同HttpApplication对象。
HttpApplicationFactory对象负责管理一个HttpApplication对象池,当有HTTP请求到来时,如果池中还有可用 的 HttpApplication对象,则分配之,否则,创建一个新的HttpApplication对象。请求完毕后,HttpApplication会 被回收以供再次使用。
每当新的HttpApplication对象创建时,都会根据配置创建新的Ihttpmodule对象,新的IHttpModule对象被创建时,其init方法就会被执行。
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 事件。(加载初始化Session时候触发)
13. 引发 PostAcquireRequestState 事件。
14. 引发 PreRequestHandlerExecute 事件。(在HTTP请求送入HttpHandler之前触发)
15. 为该请求调用合适的 IHttpHandler 类的 ProcessRequest 方法(或异步版 BeginProcessRequest)。例如,如果该请求针对某页,则当前的页实例将处理该请求。
16. 引发 PostRequestHandlerExecute 事件。(在HTTP请求送入HttpHandler之后触发)
17. 引发 ReleaseRequestState 事件。(存储Session状态的时候触发)
18. 引发 PostReleaseRequestState 事件。
19. 如果定义了 Filter 属性,则执行响应筛选。
20. 引发 UpdateRequestCache 事件。(更新缓存信息的时候触发)
21. 引发 PostUpdateRequestCache 事件。
22. 引发 EndRequest 事件。
其他
通过使用命名约定 Application_event(如 Application_BeginRequest),ASP.NET 可在 Global.asax 文件中将应用程序事件自动绑定到处理程序。这与将 ASP.NET 页方法自动绑定到事件(如页的 Page_Load 事件)的方法类似。
如果文件扩展名尚未映射到 ASP.NET,则 ASP.NET 将不会接收该请求。对于使用 ASP.NET 身份验证的应用程序,理解这一点非常重要。例如,由于 .htm 文件通常没有映射到 ASP.NET,因此 ASP.NET 将不会对 .htm 文件请求执行身份验证或授权检查。因此,即使文件仅包含静态内容,如果希望 ASP.NET 检查身份验证,也应使用映射到 ASP.NET 的文件扩展名创建该文件,如采用文件扩展名 .aspx。
如果要创建服务于特定文件扩展名的自定义处理程序,必须在 IIS 中将该扩展名映射到 ASP.NET,还必须在应用程序的 Web.config 文件中注册该处理程序。有关更多信息,请参见 HTTP 处理程序介绍。
在AcquireRequestState事件(包含该事件) 到 PostRequestHandlerExecute事件(不包含该事件)之前这段时间里,Session都是可用的。Httphandler的 ProcessRequest方法也是在这段时间内被调用的,所以用在页面中可以用Session[“key”]来访问Session。
事件 |
说明 |
BeginRequest |
指示请求处理开始。 |
AuthenticateRequest PostAuthenticateRequest |
封装请求身份验证过程。 |
AuthorizeRequest PostAuthorizeRequest |
封装请求授权过程。 |
ResolveRequestCache PostResolveRequestCache |
封装检查是否能利用以前缓存的输出页面处理请求的过程。 |
PostMapRequestHandler |
指示已发现用于处理请求的 HTTP 处理程序。 |
AcquireRequestState PostAcquireRequestState |
封装对请求会话状态的检索。 |
PostRequestHandlerExecute |
指示用于处理请求的 HTTP 处理程序已执行。 |
ReleaseRequestState PostReleaseRequestState |
封装对请求会话状态的发布。 |
UpdateRequestCache PostUpdateRequestCache |
封装检查是否应对请求的资源的输出进行缓存以备今后重复使用的过程。 |
EndRequest |
指示请求处理结束。 |
指定目标 HTTP 处理程序需要对会话状态值具有读写访问权。这是一个标记接口,没有任何方法。
作用:
在自定义 HTTP 处理程序中实现 IRequiresSessionState 接口,以确定处理程序是否需要对会话状态值具有读写访问权所以记得哦,如果在自定义HTTP处理程序中,要访问Session,记得一定要实现这个接口哦。
{
get
{
return this ._handler;
}
set
{
this ._handler = value;
this .RequiresSessionState = false ;
this .ReadOnlySessionState = false ;
this .InAspCompatMode = false ;
if ( this ._handler != null )
{
if ( this ._handler is IRequiresSessionState)
{
this .RequiresSessionState = true ;
}
if ( this ._handler is IReadOnlySessionState)
{
this .ReadOnlySessionState = true ;
}
Page page = this ._handler as Page;
if ((page != null ) && page.IsInAspCompatMode)
{
this .InAspCompatMode = true ;
}
}
}
}
代码说明:
1. 非常关键的代码 this._handler is IRequiresSessionState 和 this._handler is IReadOnlySessionState ,我们再看关于IRequiresSessionState的说明:指定目标 HTTP 处理程序需要对会话状态值具有读写访问权。而this.RequiresSessionState和this.ReadOnlySessionState默认都是false的,也就是说默认是不能访问Session的数据,当你继承IRequiresSessionState或IReadOnlySessionState之后访问权被打开!至于在哪里打开,有兴趣的朋友可以继续深究一下,在SessionStateModule这个类里面有更深入的答案,他是通过访问这个类的属性来判断是否需要打开Session的访问权的。