管道处理模型-HttpModule扩展
【一个Http请求的处理过程】

用户在浏览器输入网址,通过DNS解析得到要请求的主机IP+端口,再将请求发送到对应的服务器server(可能是多台,并不局限于一台),通过HTTP.SYS(是一个位于Win2003和WinXP SP2中的操作系统核心组件,能够让任何应用程序通过它提供的接口,以http协议进行信息通讯。)接收HTTP请求,根据端口号(一个端口号只能由一个程序响应)将请求分发给对应的应用程序去处理。
IIS就是一个运行在服务器上的应用程序,本身是不做处理的,用来分发请求,IIS将请求转发到ISAPI,在IIS中有一个【处理程序映射】,记录了不同的后缀处理采用不用的ISAPI进行处理(IIS不仅仅是用来发布.NET程序,也可以发布java、php、静态文件等)。

当请求是.NET程序时,调用aspnet_ISAPI(会将请求放在一个队列里面)做请求处理。在.NET MVC模式没有文件的后缀,在IIS6.0以前会为没有后缀的加上.axd的后缀,为经典模式,在IIS7.0以后,可以直接使用routingmodule,为集成模式,不需要加后缀,所以为了兼容IIS6.0,在MVC框架下的RouteConfig的RegisterRoutes方法下会忽略.axd的后缀路由,routes.IgnoreRoute("{resource}.axd/{*pathInfo}")。
对于.NET网站程序的入口是 HttpWorkerRequest 类,HttpWorkerRequest会一直从请求的队列获取请求,接下来交给HttpRuntime.ProcessRequest方法处理,通过反编译查看源代码可以看到,该方法接收一个HttpWorkerRequest类型的参数,做一些校验处理,再调用ProcessRequestNoDemand方法,
该方法接收HttpWorkerRequest类型的参数,还是做一些校验处理,之后再调用ProcessRequestNow方法,在这个方法中调用ProcessRequestInternal方法,该方法同样接收HttpWorkerRequest类型的参数,可以看出HttpWorkerRequest参数包含了用户发送到浏览器的全部信息。
在ProcessRequestInternal方法中,若请求超时,会响应一个503的错误,然后根据HttpWorkerRequest参数创建一个请求上下文对象HttpContext,若请求的数据有问题,这时候就会报400的错误。

请求上下文创建完成,通过HttpApplicationFactory的GetApplicationInstance方法获取或创建一个应用实例,得到一个继承自IHttpHandler接口的HttpApplication实例对象:


IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(httpContext);//返回的是一个HttpApplication实例对象,从栈缓存中获取为了对象的重用,最终是将请求的上下文交给HttpApplication实例去处理
得到HttpApplication实例对象以后,做一些常规的校验,校验没问题以后调用HttpApplication的重写方法ProcessRequest,之后结束请求this.FinishRequest(httpContext.WorkerRequest, httpContext, null);
ASP.NET的HTTP管道模型是可扩展的,可以实现自己的HTTP module、handler以及handler factory,也可以直接继承HttpApplication类,其中HttpModule是在HttpApplication实例化以后注册完成,通过HttpApplication的事件调用触发。HttpApplication提供了26个事件,其中DefaultAuthentication用interal修饰,不能做扩展,其他25个事件(正常执行是22个事件,其他三个为一些异常处理的事件)可以拿来做一些需求扩展,通过HttpContext.ApplicationInstance可以获取到本次请求的HttpApplication实例。通过HttpModule可以对事件做扩展(例如性能监控-页面响应时间、黑白名单-BeginRequest时检查是否是白名单的用户、请求日志、防爬虫、URL改写),只要继承自IHttpModule接口,在Init方法中接收一个HttpApplication对象,然后调用这个对象的25个事件添加动作即可。HttpModule是针对任何的请求的,理论上大部分的扩展都可以实现,但是不够精细,而且有性能损耗,所以我们可以在配置文件中的<module>标签移除一些系统自带但是我们并不需要的module来小小的提升性能。.NET框架默认提供的Module可以在C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\Web.config的<module>查看。

Module里面的相关事件
自己定义的module里面自定义扩展事件,在Init里面为事件添加扩展动作,事件的执行顺序是一定的,分为加载html页面前和加载页面后要执行的。当然对于框架支持的25个事件,我们也可以在自己自定义的module里面添加自定义事件,然后在Global里面实现,当加载到对应的HttpModule时,当触发到这个事件时Global就会执行这个事件的方法(例如SessionModule里面注册的Start和End事件,可以在Global里面实现Session_Start方法和Seesion_End方法,在系统添加或者移除一个Session时就会触发)。此处添加的AddHandle方法在BeginRequest触发时触发。注意:在Global里面的Application_Start和Application_Error不是Module里扩展的事件。
HttpModule处理的是针对任何请求,只要是HttpApplication处理的都可以扩展生效。

对于module的扩展,在自定义类完成以后,通过在配置文件添加相应的module
<modules>
<!--移除一些module,TelemetryCorrelationHttpModule这个为系统自带,不需要可以移除
系统自带的一些module在C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config下的Web.Config的module模块-->
<remove name="TelemetryCorrelationHttpModule"/>
<!--自定义的module-->
<add name="自定义名称" type="命名空间.类型,DLL名称">
<add name="TelemetryCorrelationHttpModule"
type="Microsoft.AspNet.TelemetryCorrelation.TelemetryCorrelationHttpModule, Microsoft.AspNet.TelemetryCorrelation"
preCondition="integratedMode,managedHandler"/>
<remove name="ApplicationInsightsWebTracking"/>
<add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web"
preCondition="managedHandler"/>
</modules>
【MVC与ASP.NET的管道模型】
MVC与ASP.NET的管道模型,在得到HttpApplication对象前都是一样的,差别在于MVC在HttpApplication对象中扩展了PostResolveRequestCache事件。前面说到在IIS7.0以后使用routingmodule对后缀加以区分,因为在UrlRoutingModule里面,通过对PostResolveRequestCache进行扩展,在这个方法里面提那家路了路由寻找机制。


可以看到在.NET框架提供的默认Module里面会有一个UrlRoutingModule,如果把这个移除掉,MVC框架就找不到对应的要访问的Controler和对应的处理方法

浙公网安备 33010602011771号