https://www.cnblogs.com/JimmyZhang/archive/2007/09/04/880967.html IHttpModule HTTPRuntime(運行時)。在一個控制台程式中,程式的入口是Program中的Main方法。那麼,一個網站的入口在哪裡呢?在最開始的ash ...
https://www.cnblogs.com/JimmyZhang/archive/2007/09/04/880967.html
IHttpModule
HTTPRuntime(運行時)。在一個控制台程式中,程式的入口是Program中的Main方法。那麼,一個網站的入口在哪裡呢?在最開始的ashx中,有個ProcessRequest方法,後來在WebForm中,在後臺是一個不分類,繼承自Page類,在Page_Load方法中去寫代碼。其實Page類型也有一個ProcessRequest的虛方法。
都是這個ProcessRequest方法來處理請求的。在MVC中也是如此。在MVC中,任何一個Http請求,一定有一個IHttpHandler來處理,在這個介面中,定義了一個ProcessRequest方法。HttpApplication繼承自IHttpHandler介面。任何一個Http請求就是一個HttpApplication對象來處理的,然後處理過程固定包含許可權認證、緩存處理、Session處理、Cookie出庫、生成html、輸出客戶端,與此同時,千千萬萬的開發者,又有各種各樣的擴展訴求,任何一個環節都有可能擴展,如果是我們來設計,該怎麼設計?
其實在MVC框架裡面,用到的是觀察者模式:
在HttpApplication類型,有這些事件:
// // 摘要: // Occurs just before ASP.NET sends HTTP headers to the client. public event EventHandler PreSendRequestHeaders; // // 摘要: // Occurs when the handler is selected to respond to the request. public event EventHandler MapRequestHandler; // // 摘要: // Occurs when the application is disposed. public event EventHandler Disposed; // // 摘要: // Occurs as the first event in the HTTP pipeline chain of execution when ASP.NET // responds to a request. public event EventHandler BeginRequest; // // 摘要: // Occurs when a security module has established the identity of the user. public event EventHandler AuthenticateRequest; // // 摘要: // Occurs when a security module has established the identity of the user. public event EventHandler PostAuthenticateRequest; // // 摘要: // Occurs when a security module has verified user authorization. public event EventHandler AuthorizeRequest; // // 摘要: // Occurs when the user for the current request has been authorized. public event EventHandler PostAuthorizeRequest; // // 摘要: // Occurs when ASP.NET finishes an authorization event to let the caching modules // serve requests from the cache, bypassing execution of the event handler (for // example, a page or an XML Web service). public event EventHandler ResolveRequestCache; // // 摘要: // Occurs when ASP.NET bypasses execution of the current event handler and allows // a caching module to serve a request from the cache. public event EventHandler PostResolveRequestCache; // // 摘要: // Occurs just before ASP.NET sends content to the client. public event EventHandler PreSendRequestContent; // // 摘要: // Occurs when ASP.NET has mapped the current request to the appropriate event handler. public event EventHandler PostMapRequestHandler; // // 摘要: // Occurs when ASP.NET has completed processing all the event handlers for the System.Web.HttpApplication.LogRequest // event. public event EventHandler PostLogRequest; // // 摘要: // Occurs when the managed objects that are associated with the request have been // released. public event EventHandler RequestCompleted; // // 摘要: // Occurs when the request state (for example, session state) that is associated // with the current request has been obtained. public event EventHandler PostAcquireRequestState; // // 摘要: // Occurs just before ASP.NET starts executing an event handler (for example, a // page or an XML Web service). public event EventHandler PreRequestHandlerExecute; // // 摘要: // Occurs when the ASP.NET event handler (for example, a page or an XML Web service) // finishes execution. public event EventHandler PostRequestHandlerExecute; // // 摘要: // Occurs after ASP.NET finishes executing all request event handlers. This event // causes state modules to save the current state data. public event EventHandler ReleaseRequestState; // // 摘要: // Occurs when ASP.NET has completed executing all request event handlers and the // request state data has been stored. public event EventHandler PostReleaseRequestState; // // 摘要: // Occurs when ASP.NET finishes executing an event handler in order to let caching // modules store responses that will be used to serve subsequent requests from the // cache. public event EventHandler UpdateRequestCache; // // 摘要: // Occurs when ASP.NET finishes updating caching modules and storing responses that // are used to serve subsequent requests from the cache. public event EventHandler PostUpdateRequestCache; // // 摘要: // Occurs just before ASP.NET performs any logging for the current request. public event EventHandler LogRequest; // // 摘要: // Occurs when ASP.NET acquires the current state (for example, session state) that // is associated with the current request. public event EventHandler AcquireRequestState; // // 摘要: // Occurs as the last event in the HTTP pipeline chain of execution when ASP.NET // responds to a request. public event EventHandler EndRequest; // // 摘要: // Occurs when an unhandled exception is thrown. public event EventHandler Error;View Code
這裡用的是觀察者模式,把固定的步驟直接卸載handler裡面,在步驟前後分別放一個事件,然後開發者可以對事件註冊動作,等著請求進來了,然後就可以按照順訊執行一下。這種設計是不是很完美?但是仍有不完美的地方,就是每個請求都要執行這些事件,太多管閑事了。在.NET Core中出現了中間件,比這種更加完美。後續再詳細介紹。
請見下列代碼
public class HttpProcessDemo { public class HttpApplicationDemo : IHttpHandler { public bool IsReusable => true; public event Action BeginRequest; public event Action EndRequest; public event Action PreSomething1Handler; public event Action PostSomething1Handler; public event Action PreSomething2Handler; public event Action PostSomething2Handler; public event Action PreSomething3Handler; public event Action PostSomething3Handler; public event Action PreSomething4Handler; public event Action PostSomething4Handler; public event Action PreSomething5Handler; public event Action PostSomething5Handler; public event Action PreSomething6Handler; public event Action PostSomething6Handler; public void ProcessRequest(HttpContext context) { this.BeginRequest?.Invoke(); this.PreSomething1Handler?.Invoke(); Console.WriteLine("Something 1"); this.PostSomething1Handler?.Invoke(); this.PreSomething2Handler?.Invoke(); Console.WriteLine("Something 2"); this.PostSomething2Handler?.Invoke(); this.PreSomething3Handler?.Invoke(); Console.WriteLine("Something 3"); this.PostSomething3Handler?.Invoke(); this.PreSomething4Handler?.Invoke(); Console.WriteLine("Something 4"); this.PostSomething4Handler?.Invoke(); this.PreSomething5Handler?.Invoke(); Console.WriteLine("Something 5"); this.PostSomething5Handler?.Invoke(); this.PreSomething6Handler?.Invoke(); Console.WriteLine("Something 6"); this.PostSomething6Handler?.Invoke(); this.EndRequest?.Invoke(); } //任何請求進來,只能是 123456 //事件升級後,可以在程式啟動時,實例化HttpApplicationDemo後,可以給事件註冊動作,請求再進來時,處理不僅是123456了,還有多個事件裡面的動作 }View Code
對HttpApplication裡面的事件進行動作註冊,就叫IHttpModule。
自定義一個HttpModule+配置文件註冊,然後任何一個請求都會執行Init裡面註冊給Application事件的動作。
public class CustomHttpModule : IHttpModule { public void Dispose() { Console.WriteLine(); } public event EventHandler CustomHttpModuleHandler; /// <summary> /// 註冊動作 /// </summary> /// <param name="context"></param> public void Init(HttpApplication application) { application.BeginRequest += (s, e) => { this.CustomHttpModuleHandler?.Invoke(application, null); }; //application.EndRequest += (s, e) => //{ // HttpContext.Current.Response.Write("CustomHttpModule.EndRequest"); //}; #region 為每一個事件,都註冊了一個動作,向客戶端輸出信息 application.AcquireRequestState += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "AcquireRequestState ")); application.AuthenticateRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "AuthenticateRequest ")); application.AuthorizeRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "AuthorizeRequest ")); application.BeginRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "BeginRequest ")); application.Disposed += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "Disposed ")); application.EndRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "EndRequest ")); application.Error += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "Error ")); application.LogRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "LogRequest ")); application.MapRequestHandler += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "MapRequestHandler ")); application.PostAcquireRequestState += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostAcquireRequestState ")); application.PostAuthenticateRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostAuthenticateRequest ")); application.PostAuthorizeRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostAuthorizeRequest ")); application.PostLogRequest += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostLogRequest ")); application.PostMapRequestHandler += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostMapRequestHandler ")); application.PostReleaseRequestState += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostReleaseRequestState ")); application.PostRequestHandlerExecute += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostRequestHandlerExecute ")); application.PostResolveRequestCache += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostResolveRequestCache ")); application.PostUpdateRequestCache += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PostUpdateRequestCache ")); application.PreRequestHandlerExecute += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PreRequestHandlerExecute ")); application.PreSendRequestContent += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PreSendRequestContent ")); application.PreSendRequestHeaders += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "PreSendRequestHeaders ")); application.ReleaseRequestState += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "ReleaseRequestState ")); application.RequestCompleted += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "RequestCompleted ")); application.ResolveRequestCache += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "ResolveRequestCache ")); application.UpdateRequestCache += (s, e) => application.Response.Write(string.Format("<h1 style='color:#00f'>來自MyCustomModule 的處理,{0}請求到達 {1}</h1><hr>", DateTime.Now.ToString(), "UpdateRequestCache ")); #endregion } }View Code
訪問下頁面,就是這樣的結果:
正常流程下,會按照順序執行19個事件。
學完HttpModule,我們可以做點什麼有用的擴展?
任何一個請求都會執行HttpModuleInit裡面註冊給Application的事件
1、日誌-性能監控
2、許可權
3、緩存
4、頁面加點東西
5、請求過濾
6、MVC就是一個Module的擴展
不適合的:不是針對全部請求的,就不太適合用Module,因為有性能損耗
1、多語言,根據Cookie信息去查詢不同的數據做不同的展示,如果是全部一套處理,最後HttpModule攔截+處理,適合httpModule
2、跳轉到不同界面,也不合適
3、防盜鏈,針對一類的尾碼來處理的,而不是全部請求---判斷----再防盜鏈
在HttpModule裡面發佈一個CustomHttpModuleHandler,在Global增加一個動作CustomHttpModuleBingle_CustomHttpModuleHandler(配置文件module名稱_module裡面事件名稱),請求響應時,該事件會執行
protected void CustomHttpModuleBingle_CustomHttpModuleHandler(object sender, EventArgs e) { this.logger.Info("this is CustomHttpModuleBingle_CustomHttpModuleHandler");
}
HttpModule是對HttpApplication的事件動作註冊動作,Global是對HttpModule裡面的事件註冊動作。