Asp.Net 请求处理机制
Asp.Net 请求处理机制
前言
我们都知道Web请求响应是基于Http协议,那么我们可以这样来理解,一次Web请求和响应的过程,实际上就是一次发送Http请求和接收Http响应的过程。
客户端向服务器发送一次Http请求,服务器端接收到这次请求,并生成响应报文
,将响应报文发送回客户端。这样客户端和服务器端就完成了一次Web交互。
什么是Asp.Net呢?
我喜欢把Asp.Net定义如:
Asp.Net 是一个运行在CLR的托管代码上,从前到后处理Web请求,并响应Web请求的一个AOP框架,它是处理Web请求的一种引擎。它不是仅仅是我们常用的WebForm,WebService,IHttpHandler这些,它还有很多.....
从浏览器到服务器的过程
我们来看一下,当我们在浏览器地址栏输入http://www.cnblogs.com博客园的网址时,并敲击回车键。这个时候就会从浏览器端生成一个Request请求,并发送给http://www.cnblgos.com的web服务器
,当请求到达web服务器的那一刻,web服务器Windows内核中的HTTP.SYS组件就会捕获到请求。当HTTP.SYS组件分析到这是一个需要交给IIS服务器处理的Http请求时,HTTP.SYS组件就会将Request请求,交给IIS服务器来处理。IIS服务器分析Request请求的context-type类型,然后从处理程序映射表中去匹配,当在处理程序映射表中能够匹配到Request请求的context-type类型时,那么IIS服务器就将请求交给映射表中所对应的程序处理。
图一 : IIS中 处理程序映射表
当IIS发现,在处理程序映射表中没有能匹配的项的时候(当没有匹配项的时候,一般情况下是请求"静态文件"),就直接去下载Request请求所对应路径的文件。如.jpg,html,xml.css文件等等。
图二 : 从浏览器到达服务器的过程
回到之前,当服务器在处理如aspx.ashx,等等动态文件的时候,IIS服务器将Request请求,交
给aspnet_isapi.dll文件来处理。
ISAPI是第一个也是性能最高Request请求报文最原始的Web请求切入点
aspnet_isapi.dll是一个非常底层,并且是非托管的win32API,这个dll非常简单,非常高效,并且还被微软优化过性能。它用来处理最底层的 指令以及函数回调,并为高层程序提供了应用程序级别服务的功能和接口。
当aspnet_isapi.dll接收到Request请求的时候,aspnet_isapi.dll就会去调动Web服务器中的.Net Framework,最终加载CLR运行环境,并创建一个ISAPIRuntime对象,然后调用ISAPIRuntime对象的ProcessRequest()方法。
ISAPIRuntme.ProcessRequest()方法是进入ASP.Net的第一个入口
ISAPIRuntime.ProcessRequest()方法调用之后主要做了一件事情,就是将Request的原始请求信息封装成HttpWorkRequest类,由于HttpWorkRequest类封装的请求报文很原始,很复杂,所以微软没有将其公开出来。接着执行StartProcessing()方法,来创建HttpRuntime对象并调用其静态方法ProcessRequest()。
图三 : 如何开始ASP.Net
HttRuntime,HttpContext,HttpApplication ?
在HttpRuntime对象调用其静态方法ProcessRequest()之后,我们的Web请求开始慢慢进入应用层级别,why?
ProcessRequest()这个方法做了很多事情,具体可以通过Reflector工具查看,但是大致分为四个部分:
1.为请求创建了一个新的HttpContext实例(这个对象就是我们常用的HttpContext上下文对象),并将HttpWorkRequest中最原始的请求报文封装到HttpContext对象的HttpRequest对象中。
2.通过HttpApplicationFactory(应用程序工厂)得到一个具体的HttpApplication 实例。
3.调用HttpApplication.Init()方法来建立事件请求管道。
4.Init()方法触发了HttpApplication.ResumeProcessing()方法来开始执行Asp.Net事件请求管道。
图四 : HttpRuntime,HttpApplication和HttpContext的关系
Asp.Net事件请求管道详解
前面说Asp.Net是一个Aop框架,而Asp.Net事件请求管道就是一点。
Asp.Net事件请求管道,是微软帮程序员提供来处理Web请求的一些列事件,这些事件是依次执行,我们可以通过在这些事件上注册或移除我们自己写的方法,来修改Web请求执行的逻辑。
图五 : ASP.Net事件请求管道
在第八个事件的时候,会创建请求的页面对象,并转换为IHttpHandler接口。
在第九个事件到第十一个事件之间,会接收到浏览器发过来的SessionId。并先会将IHttpHandler接口尝试转换为IRequiresSessionState接口,如果转换成功,Asp.Net会根据这个SessionId到服务器的Session池中去查找所对应的Session对象,并将这个Session对象赋值到HttpContext对象的Session属性。如果尝试转换为IRequiresSessionState接口不成功,则不加载Session。
在第十九个事件的时候,会调用在第八个事件创建的页面对象的ProcessRequest方法。
当我们直接使用*.ashx页面的时候,就直接调用了一个FrameworkInitialize(),并最终生成响应报文,发送回客户端。
当我们在使用*.aspx页面的时候,它继承自Page类,而Page类实现了IHttpHandler接口。
由于Page类实现了IHttpHandler接口,在ProcessRequest方法中,调用了FrameworkInitialize()方法。
在FrameworkInitialize()这个方法内部就开始打造Asp.Net的页面控件树(打造html树),在其中就调用了ProcessRequestMain方法,在这个方法里面就执行了整个Asp.Net页面生命周期。
IHttpModules
请求通过事件管道,一些列的事件被触发了,我们可以通过在Global.asax全局配置文件中看到这些事件。
但是由于这是由程序分配的事件,可能就不是我们想要的。如果我们想要创建一个能够复用的HttpApplication事件管道来处理Web请求,
我们又想将这些代码复用,或者开发成插件的形式。那么我们就可以使用IHttpModules。
IHttpModules配置很简单,我们只需要在Web.config里面配置一下就可以了。而具体的HttpModules只需要实现IHttpModules接口,并注册自己的方法就行了。
<?xml version="1.0"?>
<system.web>
<httpModules>
<add name="cnblogsHttpModules" type="cnblogs.cnblogsHttpModules"/>
</httpModules>
</system.web>
</configuration>
Web.config文件的配置
publicclass cnblogsHttpModules : IHttpModule
{
public void MyBeginRequest(object sender, EventArgs e)
{
HttpApplication application = sender as HttpApplication;
application.Context.Response.Write("这个IHttpModule具体类的写法哟!");
}
}
具体的HttpModules类写法
Asp.Net页面生命周期详解
Asp.Net是一个Aop框架,而Asp.Net事件请求管道体现了Aop思想,而现在我们要说的Asp.Net页面生命周期也体现Aop思想。
Asp.Net页面生命周期的本质就是微软提供给我们程序员修改页面控件树代码的一些列事件,我们可以通过实现页面生命周期的事件方法来修改控件树代码。
图六 : ASP.Net页面生命周期
当ASP.Net执行完我们注册的生命周期事件方法的时候,最后会调用Render方法,Render方法要求传入一个TextWriter文本写出器对象,并遍历所有控件树,调用每个控件的Render方法。
所以每一个控件调用Render方法之后产生的Html字符串都依次写入到TextWriter对象。最后ASP.Net将TextWriter中的Html字符串封装成响应报文,然后发送回客户端。
结束语
在这里,我介绍了一下ASP.Net的整个处理请求的过程。但有很多底层的信息,我还没有仔细去观察过,因此很多细节可能还是没有注意到。这篇文章可能还是有很多错误的地方,希望博客园的兄弟姐妹们纠错,谢谢。