一.HTTP请求
我们自己写的程序,是怎样进行处理的?一个完整的HTTP请求流程:
1.用户浏览器输入地址,例如 http://www.csdn.net
2.DNS解析(域名供应商):将输入的网址解析成IP+端口
3.请求到达服务器Server:IP可以在互联网上唯一定位一台服务器,而端口是用来确定进程的,端口还可以带有协议信息,用于穿过防火墙。
4.HTTP.SYS服务接收HTTP请求:
我们可以自己用IIS部署一个网站,模拟HTTP请求。顺序是部署网站----指定一个端口监听----请求到服务器----带了端口信息和协议----被HTTP.SYS监听到。HTTP.SYS是安装IIS时自动装上去的。
5.IIS将请求转发给ISAPI
IIS不能处理我们写的代码,它只能将我们的代码转发到对应的程序进行处理,它里面有一个“处理映射程序”,这里配置的是IIS的处理方式,即请求是什么后缀名,就用哪种dll处理程序进行处理,其中*.cshtml、*.aspx、*.ashx都是由asp.net_isapi.dll来进行处理,如图
因为IIS只是将请求根据后缀转发到不同的处理程序,所以我们甚至可以给java和php指定处理程序。比如将php转发给php_ISAPI,java转发给java_ISAPI,只要配置好就可以实现。
如果是js,css,html等静态文件,IIS是直接返回的。
这里有个小问题,聪明的你可能会说,像mvc这样 Home/Index,没有后缀怎么办?
IIS6和它之前都不支持mvc的,后来出现了mvc,没有后缀怎么写匹配?IIS会给没有后缀的加一个axd的后缀再处理,如图:
到了IIS7.0,就不需要这么做了。
IIS的应用程序池分为集成和经典,如图:
经典模式表明是旧的,所以一般都用集成模式,
6.HttpWorkerRequest:在上一步,会将请求包装成一个对象,通过pipeline传到这里来,这里才是asp.net开发的入口,前面是系统帮我们做好的,我们程序员是从这里开始搞事情的!
好了,终于进到我们自己写的程序中来了,看看HttpWorkerRequest的定义,如图:
7.HttpRuntime.processrequest
HttpRuntime:Http运行时,processrequest 是它下面的一个方法,看定义,如图:
ProcessRequest 方法需要一个HttpWorkerRequest参数,也就是上一步得到的。
public ActionResult Index()
{
HttpRuntime.ProcessRequest(null);//web请求的入口
return View();
}
至于ProcessRequest是怎么处理的,就要进入“管道处理模型”了。
什么是“管道处理模型”呢?就是一个请求进入到HttpRunTime之后,也就是从第7步开始,要做的事情,就叫做“管道处理模型”,因为前6步都是系统做好的,我们管不着,从第7步才开始运行我们写的代码。
我们用反编译工具打开System.Web.HttpRunTime,找到ProcessRequest
传入参数是HttpWorkerRequest类型的,如果传入null,抛出异常;如果没有使用管道模型,也抛出异常,如果都OK,就访问下一个方法 ProcessRequestNoDemand(wr)。
这里有个RequestQueue,因为Http请求也可以队列,如果队列不为空,就执行GetRequestToExecute(wr)方法进行处理,再看下面的ProcessRequestNow(wr)方法:
它调用了ProcessRequestInternal(wr)方法:
ProcessRequestInternal(wr)方法是怎么做的呢?如果被释放了(disposingHttpRuntime),那么就发送一个503的错误,"Server Too Busy",并用一个html页面来显示。如果没有被释放,就往下走,初始化一个HttpContext,它是Http请求上下文,如果初始化HttpContext失败了,就用html页面给用户返回一个400错误,下面的代码比较长,我再抓一个下面的图给大家看:
如果HttpContext初始化成功了,就把它拿到HttpApplicationFactory.GetApplicationInstance方法里面创建了一个HttpApplication对象。
每个请求都经过了上面的步骤,创建了一个HttpApplication对象,用这个HttpApplication对象来处理请求,HttpApplication是我们管道模型的核心。
通过上述步骤,终于执行到了我们写的代码,前面我们几乎没做什么,都是框架做的,我们也扩展不了。
看看HttpApplication的代码:
为什么有这么多的事件呢?因为HttpApplication要处理各种不同的请求,每个请求也许要做相同的事情,也可能不同的事情,也可能要做的事情的顺序不同,我们要把共性的部分封装起来,所以就封装成了这么多的事件(event),这样做的好处就是,遇到不同的请求,我们可以把这些事件排列和组合起来,就能完成请求的处理。
下图是对各个事件功能的介绍:
其中BeginRequest和EndRequest是方便我们做扩展的,可以在这两个方法里面加上我们要的触发动作。
PostMapRequestHandler就是把我们的请求创建一个处理器对象,我们写的MVC,Webform,都在它里面,要让它来实际执行的。
二.HttpModule
先写一段代码,用反射的方式获取所有系统自带的Http