開篇:ASP.Net是一項動態網頁開發技術,在歷史發展的長河中WebForm曾一時成為了ASP.Net的代名詞,而ASP.Net MVC的出現讓這項技術更加喚發朝氣。但是,不管是ASP.Net WebForm還是ASP.Net MVC在請求處理機制上大部分都是相同的,只是在請求處理管道上的處理事件做了不同的操作,因此,本文標題不區分ASP.Net WebForm和ASP.Net MVC,但在后續的介紹中會區分開來介紹。此外,本文以IIS經典模式為主,不討論集成模式(IIS7后加入了集成模式,不用加載外部的aspnet_isapi.dll組件)。
(1)Part 1:前奏
(2)Part 2:核心
(3)Part 3:管道
(4)Part 4:WebForm頁面生命周期
(5)Part 5:MVC頁面聲命周期
一、當一個請求到來時
①客戶端發送一個請求給服務器端
②一個HTTP請求對應一個HTTP報文
③HTTP.SYS組件捕獲請求,對報文作最基本的處理
HTTP.SYS是一個位於Windows Server和Windows XP SP2中的操作系統核心組件(內核模式中),能夠讓任何應用程序通過它提供的接口,以HTTP協議進行信息通訊。
關於內核模式與用戶模式:
在Windows Server操作系統中,一個進程既可以運行於內核模式,也可以運行於用戶模式。如果一個進程運行於內核模式,那么這個進程就可以訪問所有硬件和系統數據;如果一個進 程運行於用戶模式,那么這個進程不能直接訪問硬件,而且訪問系統數據時也會受到限制。在Intel處理器架構中一共有0~3四個特權級,內核模式運行於0級之內,而用戶模式運行於3級。通過在內核模式運行Http.SYS,偵聽器可以直接訪問TCP/IP協議棧,但是又能夠位於www服務之外,這樣就不會受到應用程序中代碼缺陷的影響,也不會因為應用程序崩潰而出現問題。
④如果該請求有緩存內容則直接響應
HTTP.SYS組件的一個重要的作用就在於它有一個緩存區,會將近期處理的響應結果放入這個緩存區之中,如果再次請求這個內容,則會從緩存區中取得內容並進行響應,提高了響應速度。而且, 靜態的內容現在被緩存於內核模式下,這使服務響應速度更快。
二、判斷是否動態資源
①IIS首先判斷請求的內容是否是靜態資源?
IIS首先會判斷請求的是否是靜態資源,如果是則直接到文件系統中拿到請求的html/css/js/jpg/gif/png等資源直接響應請求。
②如果是動態資源則先查找是由哪個擴展來處理?
IIS本身不會處理動態資源請求,它會根據請求的資源類型到一個被稱為“處理程序映射”中去查找應該由哪個擴展程序來處理這個請求。在IIS中,對於asp.net的請求一般是由aspnet_isapi.dll這個組件來進行.net運行時的加載和具體請求的處理。有了基於ISAPI的擴展擴展程序,IIS服務器就可以根據客戶端請求的資源擴展名,來決定應由哪個ISAPI擴展程序來處理客戶端請求,然后就可以將請求轉發給合適的ISAPI擴展程序。
關於IIS服務器擴展:
由於IIS服務器在設計時引入了開放的ISAPI接口標准,具備極高的可擴展性。在核心組件不變的情況下可靈活支持不同類型不同版本的ASP.NET應用程序。
關於ISAPI:
ISAPI(服務器應用編程接口),它為開發人員提供了強大的可編程能力,只要按照標准接口開發不同類型的Web應用程序的ISAPI擴展程序,就能實現對IIS功能上的擴展,從而使IIS可以處理不同類型的客戶端請求。IIS管理器提供了應用程序配置功能,可以對不同的客戶端請求配置不同的ISAPI擴展程序。ISAPI擴展程序通常以DLL形式存在,可以被IIS加載並調用。
三、一個神奇的入口
①所謂Worker Process(工作者進程)
剛剛我們大體上介紹了IIS的處理步驟,但其實IIS對於動態資源的處理首先會通過一個工作進程去加載具體的處理組件dll。以IIS 6.0為例,如果IIS判斷它自己無法處理asp.net的請求,會由W3WP.exe所維護的工作進程來加載aspnet_isapi.dll。
②.NET運行時的加載
如果Web應用程序是第一次加載,那么首先會由aspnet_isapi.dll加載.NET運行時(主要是調用服務器上的.Net Framework創建CLR運行時)。而一個IIS工作進程里有一個應用程序池,其中可以承載多個應用程序域AppDomain。
關於應用程序池:
應用程序池就是可以看成裝載計算機分配給動態網站的內存的容器。如果內存是水,那么應用程序池就是魚缸,動態網站就是魚缸中的金魚。多個動態網站可以存在於同一個應用程序池里,即魚缸中可以放多條金魚。當然,如果金魚多了,魚缸中的空間有限,金魚之間就會爭搶空間,不是很堅固的魚缸可能就會破裂,所有金魚都會受到影響。即是動態網站多了,內存不足,可能會造成內存級別的溢出漏洞,影響所有在那個應用程序池上的動態網站。關於應用程序域:
使用.NET建立的可執行程序,並沒有直接承載到進程當中,而是承載到應用程序域(AppDomain)當中。應用程序域是.NET引入的一個新概念,它比進程所占用的資源要少,可以被看作是一個輕量級的進程。
③應用程序域的加載
在.NET運行時創建好之后,通過應用程序域工廠AppDomainFactory創建應用程序域AppDomain。創建好AppDomain之后,就將請求轉給該AppDomain中的ISAPIRuntime對象,然后調用ISAPIRuntime對象的ProcessRequest()方法來進行處理。
ISAPIRuntme.ProcessRequest()方法是進入ASP.Net的第一個入口,ASP.Net的核心處理部分就剛剛開始。此篇我將其稱為前奏,是因為它是在ASP.Net的核心處理部分之前,將HTTP請求一步一步地傳遞給了ISAPIRuntime對象,后面我們再繼續探索ASP.Net的請求處理機制,今天就到此結束!
四、前奏流程總覽
參考資料
(1)Darren Ji,《ASP.NET MVC請求處理管道聲明周期的19個關鍵環節》:http://www.cnblogs.com/darrenji/p/3795661.html
(2)JackyXM,《HTTP.SYS詳解》:http://www.cnblogs.com/yxmx/articles/1652128.html
(3)木宛城主,《ASP.NET那點不為人知的事兒》:http://www.cnblogs.com/OceanEyes/archive/2012/08/13/aspnetEssential-1.html
(4)Tony He,《ASP.NET請求處理機制》:http://www.cnblogs.com/cilence/archive/2012/05/28/2520712.html