ASP.Net内部处理机制
一、IIS服务器根据请求的文件的后缀名来确定如何处理这个请求。例如.html,或.js,或.aspx…服务器获取所请求的页面的后缀名后,在服务器端寻找可以处理这类后缀名的应用程序,如果IIS找不到可以处理此类文件的应用程序,并且这个文件也没有受到服务器端的保护(一个受保护的例子就是App_Code中的文件,一个不受保护的例子就是你的js脚本),那么IIS就直接把这个文件返回给客户端。
如果服务器找到了处理此类文件的应用程序,通常称为ISAPI(Internet Server Application Programe Interface,互联网服务器应用程序接口)应用程序,他实际上只是一个接口,起到一个代理的作用,它的主要工作是映射所请求的页面(文件)和与此后缀名相对应的实际的处理程序。
例如所有的.aspx文件实际上都是由aspnet_isapi.dll这个程序来处理的,当IIS把对于.aspx页面的请求提交给了aspnet_isapi.dll以后,它就不再关心这个请求随后是如何处理的了。Asp.net只是服务器(IIS)的一个组成部分而已,它是一个ISAPI扩展。
HttpRuntime类是asp.net的一个主要入口,它有一个称作ProcessRequest的方法,这个方法以一个HttpWorkerRequest类作为参数,HttpRuntime类几乎包含着关于单个Http请求的所有信息:所请求的文件、服务器变量、QueryString、Http头信息等等。Asp.net使用这些信息来加载、运行正确的文件,并且将这个请求转换到输出流中,一般来说,也就是HTML页面。
当web.config文件的内容发生改变,或者.aspx文件发生变动的时候,为了能够卸载运行在同一个进程中的应用程序,然后再重新加载,Http请求被分放在相互隔离的应用程序域中。HTTP.SYS的内置驱动程序来监听来自外部的HTTP请求,在操作系统启动的时候,IIS首先在HTTP.SYS中注册自己的虚拟路径。
如果请求是一个可访问的URL,HTTP.SYS会将这个请求交给IIS工作者进程。IIS6.0中叫做w3wp.exe,IIS5.0中叫做aspnet_wp.exe。
除了映射文件与其对应的处理程序外,ISAPI还需要做一些其他的工作:
1、从HTTP.SYS中获取当前的Http请求信息,并且将这些信息保存到HttpWorkerRequest类中。
2、在相互隔离的应用程序域AppDomain中加载HttpRuntime
3、调用 HttpRuntime的ProcessRequest方法。
接下来才是程序员通常编写的代码所完成的工作了,然后,IIS接收返回的数据流,并重新返还给 HTTP.SYS,最后,HTTP.SYS 再将这些数据返回给客户端浏览器。
二、当Http请求进入Asp.net RunTime以后,它的管道由托管模块(Managed Modules)和处理程序(Handlers)组成,并且由管道来处理这个Http请求。
按照图中的编号了解数据是如何流动的:
① HttpRuntime将Http请求转交给HttpApplication,HttpApplication代表着程序员创建的Web应用程序。HttpApplication创建针对此Http请求的HttpContext对象,这些HttpContext对象包含了关于此请求的诸多其他对象,主要有HttpRequest、HttpResponse、HttpSessionState等。这些对象在程序中可以通过Page类或者Context类进行访问。
② 接下来Http请求通过一系列Module,这些Module对Http请求具有完全的控制权。这些Module可以做一些执行某个实际工作前的事情。
③ Http请求经过所有的Module之后,它会被HttpHandler处理。
④ HttpHandler处理完以后,Http请求再一次回到Module,此时Module可以做一些某个工作已经完成了之后的事情。
三、Http管道中有两个可用的接口。一个是IHttpHandler,一个是IHttpModule。通过查看“处理程序映射”,发现好多文件都交给aspnet_isapi.dll去处理了。很明显,aspnet_isapi.dll不可能对每种文件采用同一种方式处理,所以在C:、WiNDOWS\Microsoft.NET\Framework\v2.0.50727\Config\目录下web.config文件中的<httpHandlers>节点中将不同的文件类型映射给不同的Handler去处理,对于.aspx来说,是由System.Web.UI.Page.HandlerFactory来处理。
1 <httpHandlers>
2
3 ……
4
5 <add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True" />
6
7 <add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True" />
8
9 <add path="*.asmx" verb="*" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False" />
10
11 <add path="*.rem" verb="*" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="False" />
12
13 <add path="*.soap" verb="*" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="False" />
14
15 <add path="*.asax" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />
16
17 <add path="*.ascx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />
18
19 <add path="*.master" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />
20
21 ……
22
23 <add path="*" verb="GET,HEAD,POST" type="System.Web.DefaultHttpHandler" validate="True" />
24
25 <add path="*" verb="*" type="System.Web.HttpMethodNotAllowedHandler" validate="True" />
26
27 </httpHandlers>
.Net Framework在处理Http请求时采用默认Handler,而如果要操控一个Http请求,就需要实现IHTTPHandler接口,而实现IHttpHandler接口的类就是一般处理程序。
1 // 摘要:
2
3 // 定义 ASP.NET 为使用自定义 HTTP 处理程序同步处理 HTTP Web 请求而实现的协定。
4
5 public interface IHttpHandler
6
7 {
8
9 bool IsReusable { get; }
10
11 void ProcessRequest(HttpContext context);
12
13 }
该接口中包含一个属性和一个方法,其中ProcessRequest方法中的代码是处理请求的主要代码。IsReusable属性,该值指示其他请求是否可以使用IHttpHandler实例,也就是说后继的Http请求是不是可以继续使用实现了该接口的类的实例,为true时可以,否则不可以。下面是一个自定义的处理程序:
1 public class Handler1 : IHttpHandler
2 {
3 public void ProcessRequest(HttpContext context)
4 {
5 //处理请求的代码
6 }
7 public bool IsReusable
8 {
9 get
10 {
11 return true;
12 }
13 }
14 }
创建一个自定义的HttpHandler后,为了让它能够处理某些HTTP请求,还需要将它注册到web.config中:
1 <httpHandlers>
2
3 <add verb="*" path="*.jpg" type="Test_js.Handler1"/>
4
5 </httpHandlers>
path:指的是请求的文件名称,可以使用通配符扩大范围,也可以明确指定这个Handler仅用于处理某个特定的文件的请求。
verb:指的是请求此文件的方式,可以使post或get,用*代表所有的访问方式。
type:程序集.类名
IHttpFactory接口概述:
1 public interface IHttpHandlerFactory
2
3 {
4
5 IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated);
6
7 void ReleaseHandler(IHttpHandler handler);
8
9 }
GetHandler方法中的参数介绍:
context:System.Web.HttpContext 类的实例,它提供对用于为 HTTP 请求提供服务的内部服务器对象(如 Request、Response、Session和 Server)的引用。
requestType:客户端使用的 HTTP 数据传输方法(GET 或 POST)。
url:所请求资源的 System.Web.HttpRequest.RawUrl。
pathTranslated:所请求资源的 System.Web.HttpRequest.PhysicalApplicationPath。
该接口中定义了2个方法,GetHandler方法在请求开始的时候被调用,而ReleaseHandler在请求结束,所有的Handler都不在需要的时候被调用。
一个HandlerFactory可以处理N个HttpHandler,什么时候该处理什么HttpHandler就在这里的处理逻辑中实现。
什么时候使用IHttpHandlerFactory:
1、在一个项目中需要使用很多IHttpHandler的时候,而且对这些IHttpHandler判断都重复做一个同样的前期处理。
2、从部署和松散耦合考虑,如果你的web application足够大,你就要考虑在更换HttpHandler处理类的时候该不该去改动Web.config的配置,这种改动将会重新启动整个app,对于一些系统而言这是不可以随便进行的。这个时候,统一一个入口的IHttpHandlerFactory很重要,这个入口相对不变,而IHttpHandler实现可以通过外挂自定义的xml文件来实现松散耦合,运用一些反射什么的就可以实现了。
三、HttpModule是实现了IHttpModule接口的程序集,HttpModule的作用是与应用程序事件相关的。
1 public interface IHttpModule
2
3 {
4
5 void Dispose();
6
7 void Init(HttpApplication context);
8
9 }
Init()方法:这个方法接受一个HttpApplication对象,HttpApplication代表了当前的应用程序,在这个方法中注册对事件进行注册。
Dispose():它可以在进行垃圾回收之前进行一些清理工作。
通过在Http请求管道中注册期望对应用程序事件作出反应的方法,在相应的事件触发的时候,便会调用HttpModule注册了的方法,实际的工作在这些方法中执行。
自定义的HttpModule需要我们自己在web.config文件中对其进行注册:
1 <system.webServer>
2 <modules>
3 <add name="MyModule" type="WebApplication1.ModuleDemo,WebApplication1"/>
4 </modules>
5 </system.webServer>
整个过程:
1、当站点第一个资源被访问的时候,Asp.Net会创建HttpApplication类的实例,它代表着站点应用程序,同时会创建所有在Web.Config中注册过的Module实例。
2、在创建Module实例的时候会调用Module的Init()方法。
3、在Init()方法内,对想要作出响应的HttpApplication暴露出的事件进行注册。(仅仅进行方法的简单注册,实际的方法需要另写)。
4、HttpApplication在其应用程序周期中触发各类事件。
5、触发事件的时候调用Module在其Init()方法中注册过的方法