本文是自己查看源碼后的個人總結,不保證其準確性。大家可作為參考。 瀏覽器和服務器之間的通信。 當敲一個域名到瀏覽器上面,然后回車的時候,如:http://www.baidu.com/index.aspx 瀏覽器會按照HTTP協(xié)議的語法生成相應的請求報文。 瀏覽器檢查本機是否保存了http://www.baidu.com/index.aspx域名對應的服務器IP地址。如果沒有,則發(fā)送請求到所在城市網中最近的DNS服務器(域名解析服務器),它會根據我們發(fā)送來的域名查詢到該域名對應的服務器IP地址,并發(fā)送回瀏覽器。 瀏覽器DNS服務器獲得了這個域名所對應的服務器電腦的IP然后在龐大的互聯網中找到這個對應的服務器 HTTP協(xié)議規(guī)定服務器軟件如(iis)使用的默認端口是80端口,也就是說瀏覽器默認的將HTTP請求報文發(fā)送到對應服務器的80端口。 服務器接受到瀏覽器發(fā)送到的HTTP請求報文(具體報文用httpwatcher查看)。 下面是發(fā)送到百度的請求報文: 服務器分析請求報文中的路徑和文件名,在服務器找到這個文件。 如果是CSS和html,js,圖片等文件就直接在服務器上面讀取這個文件發(fā)送給瀏覽 器客戶端。 下面是對ASP.NET動態(tài)頁面的處理 當服務器IIS發(fā)現你請求的頁面是動態(tài)頁面,他發(fā)現他自己處理不了。 打開IIS,會發(fā)現里面有個處理程序映射
,也就是說IIS會將我們的.aspx后綴的文件交給對應的處理程序(aspnet_isapi.dll)。這里簡稱ISAPI。 ISAPI就會將請求交給.NET framework。 再有ISAPI將請求交給ASP.NET,也就是一個名為aspnet_wp.exe的工作進程aspnet_wp.exe就調用FrameWork里的類 ------- ISAPIRuntime。 下面是用反編譯工具來分析的這個類ISAPIRuntime 看到這個方法,就會想到了垃圾回收。 其實這不是重點。重點是 點擊這個方法進去 首先會創(chuàng)建一個ISAPIWorkerRequest的對象wr,將請求報文封裝到wr中 然后調用這個類的CreateWorkerRequest方法實例化這個對象 進入這個方法 這個方法會根據當前的IIS版本創(chuàng)建不同的對象 再回到ProcessRequest方法 接著就會調用HttpRuntime的ProcessRequestNoDemand方法。將wr傳進去 進入這個方法 在這個方法的最后會調用 ProcessRequestNow方法。處理請求 這個方法有調用了另一個方法。進去 這里就會發(fā)現一個熟悉的東西,HttpContext(上下文對象) 這個方法會根據上面創(chuàng)建的ISAPIWorkerRequest對象wr(封裝了請求報文)創(chuàng)建HttpContext。如果創(chuàng)建出錯,就會返回一個400的錯誤。 判斷是否是第一次請求之前 (如果是第一次請求,就設置當前的時間為第一次請求的起始時間。初始化第一次請求。設置第一次請求為false) 初始化Response. 當httpwriter為空的時候,就創(chuàng)建??梢钥吹?/span>,context.response中有2個寫出器 一個是httpwriter,一個是textwriter 然后通過HttpApplicationFactory創(chuàng)建一個HttpApplication對象(此對象負責真正處理頁面對象的創(chuàng)建和執(zhí)行,先在httpapplication池中看又沒有這個對象,沒有就new一個) 下面打開HttpApplication這個類 在這里面最重要的就是這25個事件。其中有19個事件開放給我們使用。 1,BeginRequest HTTP管道開始處理請求時,會觸發(fā)BeginRequest事件 2-3,AuthenticateRequest,PostAuthenticateRequest ASP.NET先后觸發(fā)這兩個事件,使安全模塊對請求進行身份驗證,。 4-5,AuthorizeRequest,PostAuthorizeRequest ASP.NET先后觸發(fā)這兩個事件,使安全模塊對請求進程授權 6-7,ResolveRequestCache,PostResolveRequestCache ASP.NET先后觸發(fā)這兩個事件,以使緩存模塊利用緩存的直接對請求直接進程響應(緩存模塊可以將響應內容進程緩存,對于后續(xù)的請求,直接將緩存的內容返回,從而提高響應能力)。 8,PostMapRequestHandler 對于訪問不同的資源類型,ASP.NET具有不同的HttpHandler對其進程處理。對于每個請求,ASP.NET會通過擴展名選擇匹配相應的HttpHandler類型,成功匹配后,該實現被觸發(fā) 9-10,AcquireRequestState,PostAcquireRequestState ASP.NET先后觸發(fā)這兩個事件,使狀態(tài)管理模塊獲取基于當前請求相應的狀態(tài),比如SessionState 11-12,PreRequestHandlerExecute,PostRequestHandlerExecute ASP.NET最終通過一請求資源類型相對應的HttpHandler實現對請求的處理,在實行HttpHandler前后,這兩個實現被先后觸發(fā) 13-14,ReleaseRequestState,PostReleaseRequestState ASP.NET先后觸發(fā)這兩個事件,使狀態(tài)管理模塊釋放基于當前請求相應的狀態(tài) 15-16,UpdateRequestCache,PostUpdateRequestCache ASP.NET先后觸發(fā)這兩個事件,以使緩存模塊將HttpHandler處理請求得到的相應保存到輸出緩存中 17-18,LogRequest,PostLogRequest ASP.NET先后觸發(fā)這兩個事件為當前請求進程日志記錄 19,EndRequest 整個請求處理完成后,EndRequest事件被觸發(fā) 在第8個事件創(chuàng)建被請求頁面類的對象,并轉換成Ihttphandler接口類對象。, 在9-10事件中會接受瀏覽器發(fā)送過來的sessionid,并且根據此值到服務器的session池中找到相對應的session對象,并將它賦值給頁面類對象的session屬性。 在第11到12事件之間執(zhí)行頁面類的processrequest方法。 下面是狀態(tài)保持:session,cookie viewstate。寫完狀態(tài)保持再仔細將在11到12事件中具體做了什么事情 Cookie是保存在瀏覽器端的,cookie有兩種狀態(tài),一種是保存在客戶端電腦的內存中,當訪問頁面的時候創(chuàng)建的cookie(也就是沒有設置過期時間的cookie)。還有一種是設置了過期時間為正的cookie,是保存在瀏覽器所對應的cookie文件夾中的。設置cookie前,瀏覽器發(fā)送請求到服務器,服務器要對該瀏覽器設置cookie,所以就發(fā)送一個cookie到瀏覽器,保存在客戶端的內存或者硬盤中。當設置了cookie后,每次請求頁面都會把cookie發(fā)送到服務器 Session是依賴于cookie實現的。不同的是session是保存在服務器端的。 例如,當我們登陸的時候,服務器那邊會給我們設置一個session保存在服務器端,然后會產生一個sessionid發(fā)送到瀏覽器端,瀏覽器這邊存儲這個sessionid,當你再請求別的頁面的時候,瀏覽器就會將這個sessionid發(fā)送到服務器。,服務器根據從瀏覽器發(fā)送過來的sessionid自動從服務器的session池中找到與這個sessionid想對應的session對象并賦值給當前頁面對象的session屬性。 如果瀏覽器禁用了Cookie的話,那服務器也可以通過將sessionId保存在url中來完成sessionid在瀏覽器和服務器間的傳遞。(需要設置配置文件里的 sessionState節(jié)點的 cookieless="autodetect") <sessionState cookieless="AutoDetect"></sessionState> Viewstate:頁面的viewstate屬性實際上就是獲取了瀏覽器提交過來的一個名位__VIEWSTATE的隱藏域里面的值。 使用viewstate必須要有一個runat=“server”的表單 在頁面類對象執(zhí)行processrequest方法的時候,先創(chuàng)建控件樹,然后通過執(zhí)行loadstate方法,將請求報文中的名為__VIEWSTATE反base64編碼然后進行序列化,最終還還原成集合,再將其中屬于程序員自己添加的viewstate里面的鍵值對還原到頁面對象的viewstate屬性中,然后再執(zhí)行page_load。,然后執(zhí)行savestate將數據保存到viewstate屬性中。 那么在第11到12之間中執(zhí)行了頁面類對象的processrequest方法,到底做了什么呢 。 1, 調用父類的processrequest方法,在此方法中父類調用父類的FrameworkInitialize()方法,但因為被頁面類重寫了,所以執(zhí)行的是當前頁面類的FrameworkInitialize()方法。在中間調用了_buildControlTree 2, 打造控件樹 前臺頁面類繼承自后臺頁面類。
后臺頁面類繼承自page
Templatecontrol繼承自control 在coltrol類中 在中間有一個control集合 也就是說我們的前臺頁面類根據繼承關系包含了一個控件集合。 再來到前臺頁面類。 ,在最后面發(fā)現一個ProcessRequest方法。 Bulidcontroltree開始打造控件樹。 前臺類繼承后臺類 litralControl包含html代碼的第一段。 Htmlhead-htmltitle...... _BuildControlTree這個方法會將前臺的所有代碼封裝起來,根據不同的標簽封裝成不同的控件對象。 3, 執(zhí)行頁面生命周期 1. Page_Init();
4, 調用頁面類的Render方法生成html代碼。 上面貌似很亂 。下面整理一下。 1, 瀏覽器請求一個動態(tài)頁面。IIS發(fā)現自己不能處理,將請求轉給映射表。 2, 映射程序里面aspx頁面對應的是aspnet_isapi.dll,于是就將請求轉給ISAPI 3, 請求報文通過ISAPIRuntime交給了HttpRuntime。 4, 在HttpRuntime里面創(chuàng)建了ISAPIWorkerRequest的對象wr,將請求報文封裝到wr中。再通過一系列方法創(chuàng)建HttpContext上下文對象,里面包含HttpRequest和HttpResponse。 5, 然后通過HttpApplicationFactory創(chuàng)建一個HttpApplication對象(此對象負責真正處理頁面對象的創(chuàng)建和執(zhí)行,先在httpapplication池中看又沒有這個對象,沒有就new一個) 6, 在httpapplication請求管道中調用19個標準的處理事件。 在第8個事件中創(chuàng)建被請求的頁面類對象 在第9-10事件中接受瀏覽器發(fā)送過來的sessionid,并且根據此值到服務器的session池 中找到相對應的session對象,并將它賦值給頁面類對象的session屬性。 第11-12事件執(zhí)行頁面類的processrequest方法。打造控件樹,執(zhí)行頁面生命周期,調用頁面類中所有控件對象的Render方法,生成html代碼 7, 將html代碼返回給瀏覽器。 |
|