网站通信就是浏览器(客户端)与网站(服务器)之间的交互。双方通过通信套接字来发送和接受通信报文进行信息交互。
服务器处理页面的流程:
1.服务器接受到由浏览器发送过来的请求报文后,在服务器软件的帮助想获得对应的页面路径,在服务端的硬盘里找出所对应的网站页面程序,如果是静态文件(只包含html,css,image,javascript),则将其解析到相应报文里,直接发送回客户端。如果是动态文件,则要将其送给服务器的扩展程序来运行(由于IIS出来的时候还没有asp.net,所以处理动态页面的程序是IIS的扩展程序)。
2.Framework执行其扩展程序,里面的ISAPIRunTime调用一些非托管代码生成HttpWorkerRequest对象,HttpWorkerRequest包含当前请求报文里面的所用信息,然后将其传递给HttpRunTime对象。
3.HttpRunTime对象根据HttpWorkerRequest对象生成HttpContext上下文对象,HttpContext包含Request和Response等重要属性。Request属性本质就是一个装请求报文的容器,里整理了请求报文的各个信息,方便程序员的调用;而Response属性则与HttpContext相对应,是一个用于存放相应报文的容器,用于存放相应报文的各个部分。
4.接着HttpRunTime对象调用了HttpApplicationFactory来生成一个实现了IHttpHandler接口的HttpApplication对象。但,在创建HttpApplication之前,它先会查看是否存在global.asax文件(Framework会在读取配置文件的时候判断是否存在<modules>节点来判断
是否存在global.asax),如果有的话就遍历<modules>里面的每个子节点,获得每个过滤器程序集里的类,并一次性创建然后将类转成IHttpModule接口对象,然后存入一个静态集合中(过滤器集合)。
5.接着创建HttpApplication对象,遍历过滤器集合,调用Init方法为HttpApplication里的事件注册用户定义的方法。其实就是将请求管道里面注册用户自定义的事件(面向方面编程),使得每次都会执行着些自定义的方法。接着就会执行HttpApplication对象的RrocessRequest方法,并将上下文对象HttpContext传入。
6.HttpApplication对象的RrocessRequest方法其实就是所谓的“请求管道”。里面包含有25个事件,其中有19个时间供程序员用。里面的事件就是就是刚刚我们在过滤器注册进来的事件。而在第八个事件的时候,就创建了被请求前台页面类对象(前台页面类继承于其对应的后台页面类,后台页面类继承了Page类,Page类继承了TemplateControl类,TemplateControl类继承了Control类,Control类定义了许多重要的属性,例如ViewState属性。)。
7.执行到请求管道的第十个事件中,会加载Session。首先会尝试将页面类对象转换成IPequiresSessionState接口对象,如果转换不成功就不加载Session对象,如果转换成功,则从请求报文中获得cookie里的SessionId,然后到服务器的Session池中,根据SessionId找出对应的Session对象,并将其引用赋值给页面对象的上下文对象的Session属性。
8.在请求管道的第十一和十二个事件之间,就会调用了页面对象父类继承来的ProcessRequest方法。在次方法中,首先调用了父类的FrameworkInitialize()方法,但因为被页面类重写了,所以执行的是当前页面类的FrameworkInitialize(),在中间就调用了_buildControlTree()方法来打造控件树。打造控件树就是将程序员在前台页面的所有代码转成控件Control类对象,然后添加到被请求的页面对象的Control集合中。
9.执行完_buildControlTree()方法后,就会调用ProcessRequestMain方法,在此方法里面就执行了整个页面生命周期(页面生命周期,其实就是调用了一系列的事件方法)。页面生命周期里面的方法是打造整个页面的最重要方法,下面的几个方法是我们必须知道的:
(1)LoadState:将表单的隐藏域_VIEWSTATE里的数据设置到页面对象ViewState属性中,ViewState属性由Control类创建,前台页面类根据继承关系也就拥有了ViewState属性。LoadState方法里首先尝试从请求报文里面获取_VIEWSTATE的值,如果有则将这个值反base64编码,然后反序列化,将会取得对象键值对存入页面类的ViewState属性中(服务端软件里的StateBag-Dictionary)。(Ps:隐藏域里不仅仅使包含用户ViewState保存的数据,还包含所有服务器控件的属性参数。)
(2)ProcessPostData:将表单里提交的控件数据设置给页面对象的控件树种对控件的属性。
(3)PageLoad:调用程序员在后台的Page_Load中编写的代码,此时程序员可以通过访问空间属性的方式获得浏览器提交的表单控件值,或者重新创建新的控件到空间树中。
(4)ProcessPostData Second:在次设置控件树的属性,此举主要是为了让在PageLoad方法中创建的控件赋值(值来自表单提交的数据)。
(5)RaiseChangeEvents:执行控件非点击回传事件。
(6)RaisePostBackEvent:执行控件的点击回传事件。
(7)SaveState:将控件的状态属性存入页面的ViewState中。将页面ViewState属性里的所有键值对,都进行序列化,并进行base64编码,然后将这些值添加到一个字符串变量中。
(8)Render:递归调用控件树里每个空间的Render来生成整个页面的html代码,同时会将之前ViewState所生成的字符串作为_VIEWSTATE隐藏域,添加到html代码中,最后存入Response中。
(9)卸载页面生命周期,继续执行请求管道里的事件。
10.当请求管道的事件都执行完后,HttpApplication对象就会将Response属性的值发给服务器软件生成相应报文,最后发送给浏览器。这样,整个页面交互就完成了。