要介紹這兩個內容,必需要從ASP.NET管線提及。javascript
管線(Pipeline)這個詞形象地說明了每一個Asp.net請求的處理過程: 請求是在一個管道中,要通過一系列的過程點,這些過程點鏈接起來也就造成一條線。 這些一系列的過程點,其實就是由HttpApplication引起的一系列事件,一般能夠由HttpModule來訂閱, 也能夠在Global.asax中訂閱,這一系列的事件也就構成了一次請求的生命週期。html
下面經過兩張圖片來詳細說明一下請求的過程java
第一張圖,主要展現:請求的過程jquery
從上面的圖中,咱們能夠看出ajax
1.請求先交給HttpModule處理,而後由HttpModule交給HttpHandler,最後再由HttpHandler交回給HttpModule,由HttpModule結束請求。正則表達式
2.Session的有效期,只有在HttpHandler處理時有效。HttpModule處理時,都是無效的。緩存
3.整個過程由一系列的事件組成,這點正應驗了前面對管線的定義。服務器
第二張圖,主要說明:管線中全部事件的意義app
注意:這是iis7的處理過程,其中多了LogRequest與PostLogRequest這兩個事件。iis6的處理過程並無這兩個事件。框架
對於各個事件的含義,我想圖片已經解釋的很清楚了。
下面經過一個案例,來說解一下本篇博客的主題。
案例需求:第三方以這樣的url:http://host:port/xxxx/mobile/form?Id=xxxxx。向系統發出請求時。系統能夠將該url映射到對應的業務層。因爲本次主要講解的重點不在業務層,因此就將該url直接映射到一個簡單業務層,輸入Hello+Query
中心思想:將請求的url重寫成服務器能夠處理的url形式。而後由服務器根據重寫後的url,查找出能夠處理重寫後的url的Handler,最後由Handler對其進行處理。
思路:
1.定義url重寫後的樣子。好比將url:http://host:port/xxxx/mobile/form?Id=xxxxx。重寫成:http://host:port/xxxx/mobile/service.mobile?Id=xxxxx。
2.編寫自定義Module:IHttpModule,檢測url是不是須要重寫的url,若是是重寫url。由管線根據重寫後的url來尋找對應的Handler對其進行處理。
3.編寫自定義Handler:IHttpHandler,來處理重寫後的url。
步驟:
1.編寫自定義Module
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web; namespace Service { /// <summary> /// url重寫Module /// </summary> internal class UrlRewriteModule : IHttpModule { /* * 爲了演示簡單,直接寫死地址 * 這裏我寫了兩個url,一個從虛擬路徑的根路徑重寫(我本機的虛擬路徑是/Web);另外一個從url的末尾處重寫 * 具體用哪一個url,根據需求。可是有一點要注意,若是採用根路徑重寫方式, * 那麼服務器上的虛擬路徑、重寫後的url的虛擬路徑、Web.config中<httpHandlers>節點下配置的path的虛擬路徑都必須相同, * 不然Module沒法根據url映射對應的Handler */ public static string rootUrlPattern = "/Web/service.mobile"; //public static string urlPattern = "service.mobile"; public void Init(HttpApplication app) { app.PostAuthorizeRequest += app_PostAuthorizeRequest; } void app_PostAuthorizeRequest(object sender, EventArgs e) { HttpApplication app = sender as HttpApplication; //檢測是不是要重寫的url(這裏最好用正則表達式匹配) if (app.Context.Request.Url.PathAndQuery.Contains("mobile/form")) { //檢查url中是否帶有參數 int p = app.Request.Path.IndexOf("?"); if (p > 0) { //重寫url,而且將url參數進行拼接 app.Context.RewritePath(rootUrlPattern + "&" + app.Request.Path.Substring(p + 1)); } else { //重寫url(url中不帶參數) app.Context.RewritePath(rootUrlPattern); } } } public void Dispose() { } } }
2.編寫自定義Handler
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web; namespace Service { public class UrlHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { HttpRequest request = context.Request; string result = string.Empty; if (!string.IsNullOrEmpty(request.Form["ID"])) { string id = request.Form["ID"]; result = "Hello " + id; } else { result = "Hello"; } context.Response.Write(result); } public bool IsReusable { get { return false; } } } }
3.Web.config配置
<httpHandlers> <add path="/Web/service.mobile" verb="*" validate="false" type="Service.UrlHandler,Service"/> </httpHandlers> <httpModules> <add name="UrlRewriteModule" type="Service.UrlRewriteModule,Service"/> </httpModules>
4.測試頁面
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script src="Scripts/jquery-1.8.2.js" type="text/javascript"></script> <script type="text/javascript"> function formTest() { $.ajax({ type: "POST", url: "mobile/form", data: { ID: "wolf" }, complete: function (XHR, TS) { XHR = null; }, success: function (msg) { alert(msg); } }); } </script> </head> <body> <input type="button" value="發起請求" onclick="formTest();" /> </body> </html>
以上代碼有2點須要說明
1.選擇註冊PostAuthorizeRequest(用戶已經獲得受權)事件中重寫url。由於
a.用戶驗證,用戶受權都讓其按照asp.net框架自行運行。
b.PostAuthorizeRequest的下一個事件是ResolveRequestCache(獲取之前處理緩存的處理結果)。若是本次請求的url在以前處理過,那麼會直接點用緩存結果,而不會再進行處理工做。若是我寫在ResolveRequestCache事件以後,若是緩存中有處理結果。那麼後面的事件都有可能被跳過(EndRequest不會被跳過)。因此我選擇在PostAuthorizeRequest事件中重寫url。
2.自定義Module中,有關於url重寫時須要注意虛擬路徑的一段描述。
若是採用根路徑重寫方式,那麼服務器上的虛擬路徑、重寫後的url的虛擬路徑、Web.config中<httpHandlers>節點下配置的path的虛擬路徑都必須相同,不然Module沒法根據url映射對應的Handler。
中心思想:檢測url是不是須要處理的格式。而後直接指定Handler對重寫後的url進行處理(這點就是url路由與url重寫的區別,url路由是指定Handler來對重寫後的url進行處理,而url重寫是交給管線,讓其尋找能處理重寫後的url的Handler)
思路:
1.編寫自定義Module:IHttpModule,檢測url是不是須要處理的格式,若是是由管線根據重寫後的url來尋找對應的Handler對其進行處理。
2.編寫自定義Handler:IHttpHandler,來處理重寫後的url。
步驟
1.編寫自定義Module
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web; namespace Service { /// <summary> /// URL路由 /// </summary> internal class UrlRoutingModule : IHttpModule { public void Init(HttpApplication app) { app.PostResolveRequestCache += app_PostResolveRequestCache; } void app_PostResolveRequestCache(object sender, EventArgs e) { HttpApplication app = sender as HttpApplication; //檢測是不是要重寫的url(這裏最好用正則表達式匹配) if (app.Context.Request.Url.PathAndQuery.Contains("mobile/form")) { app.Context.RemapHandler(new UrlHandler()); } } public void Dispose() { } } }
2.編寫自定義Handler
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web; namespace Service { internal class UrlHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { HttpRequest request = context.Request; string result = string.Empty; if (!string.IsNullOrEmpty(request.Form["ID"])) { string id = request.Form["ID"]; result = "Hello " + id; } else { result = "Hello"; } context.Response.Write(result); } public bool IsReusable { get { return false; } } } }
3.Web.config配置(只須要配置httpModules節點)
<httpModules> <add name="UrlRoutingModule" type="Service.UrlRoutingModule,Service"/> </httpModules>
4.測試頁面
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script src="Scripts/jquery-1.8.2.js" type="text/javascript"></script> <script type="text/javascript"> function formTest() { $.ajax({ type: "POST", url: "mobile/form", data: { ID: "wolf" }, complete: function (XHR, TS) { XHR = null; }, success: function (msg) { alert(msg); } }); } </script> </head> <body> <input type="button" value="發起請求" onclick="formTest();" /> </body> </html>
以上代碼有2點須要說明
1.PostMapRequestHandler(根據用戶請求,建立處理請求對象)事件是asp.net框架根據請求選擇Handler的事件。因此,若是想自定義選擇Handler,必定要選擇管線中在其事件以前的事件。而比較早的事件,例如:驗證用戶事件、受權事件,都讓asp.net框架幫咱們處理。
2.本次在Web.config配置中,只要配置httpModule節點就能夠。由於url路由是自定義選擇Handler,並不須要asp.net框架根據請求選擇對應的Handler,因此Handler節點不須要任何配置。
感謝你們的耐心閱讀。