成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

選擇HttpHandler還是HttpModule?

開發(fā) 后端
我原以為在博客 用Asp.net寫自己的服務(wù)框架 中做了那么多的演示應(yīng)該把它們的使用方法說清楚了,然而有些人看了我的那些示例,仍然不知道該如何選擇它們,為了實(shí)現(xiàn)同一個目標(biāo),我既用了HttpHandler,也有用HttpModule。

最近收到幾個疑問:HttpHandler和HttpModule之間有什么差別,我到底該選擇哪個?

之所以有這個疑問,是因?yàn)樵谶@二類對象中都可以訪問Request, Response對象,都能處理請求。

我原以為在博客 用Asp.net寫自己的服務(wù)框架 中做了那么多的演示應(yīng)該把它們的使用方法說清楚了,然而有些人看了我的那些示例,仍然不知道該如何選擇它們,為了實(shí)現(xiàn)同一個目標(biāo),我既用了HttpHandler,也有用HttpModule。現(xiàn)在看來,我當(dāng)時設(shè)計(jì)的那些示例并不是講清楚HttpHandler和HttpModule之間有什么差別,而是在演示如何利用HttpHandler和HttpModule設(shè)計(jì)一個服務(wù)框架。

很慶幸那篇博客內(nèi)容沒有走題,今天只好再來寫一篇了。

本文約定:

1. HttpHandler泛指所有實(shí)現(xiàn)IHttpHandler接口的類型。

2. HttpModule泛指所有實(shí)現(xiàn)IHttpModule接口的類型。

因此,本文將不會特別區(qū)分這些類型與接口。

理解ASP.NET管線

HttpHandler和HttpModule,它們都與ASP.NET管線有關(guān),所以我想理解這二類對象必須要理解ASP.NET管線的工作方式。

下圖反映了ASP.NET管線的處理流程:

ASP.NET管線處理流程

這是一張時序圖,我們應(yīng)該從二個角度來理解它:

1. 有哪些調(diào)用動作。2. 有哪些參與者。

每個調(diào)用動作,都反映了ASP.NET管線的處理階段,它們會引發(fā)相應(yīng)的事件(除GetHandler,ProcessRequest之外), HttpModule則會訂閱這些事件,參與到管線處理過程。這些階段中,有些階段還引發(fā)了二個事件,完整的管線事件可參考MSDN文檔:

  1. 在處理該請求時將由 HttpApplication 類執(zhí)行以下事件。 希望擴(kuò)展 HttpApplication 類的開發(fā)人員尤其需要注意這些事件。  
  2. 1. 對請求進(jìn)行驗(yàn)證,將檢查瀏覽器發(fā)送的信息,并確定其是否包含潛在惡意標(biāo)記。 有關(guān)更多信息,請參見 ValidateRequest 和腳本侵入概述。  
  3. 2. 如果已在 Web.config 文件的 UrlMappingsSection 節(jié)中配置了任何 URL,則執(zhí)行 URL 映射。  
  4. 3. 引發(fā) BeginRequest 事件。  
  5. 4. 引發(fā) AuthenticateRequest 事件。  
  6. 5. 引發(fā) PostAuthenticateRequest 事件。  
  7. 6. 引發(fā) AuthorizeRequest 事件。  
  8. 7. 引發(fā) PostAuthorizeRequest 事件。  
  9. 8. 引發(fā) ResolveRequestCache 事件。  
  10. 9. 引發(fā) PostResolveRequestCache 事件。  
  11. 10. 根據(jù)所請求資源的文件擴(kuò)展名(在應(yīng)用程序的配置文件中映射),選擇實(shí)現(xiàn) IHttpHandler 的類,對請求進(jìn)行處理。 如果該請求針對從 Page 類派生的對象(頁),并且需要對該頁進(jìn)行編譯,則 ASP.NET 會在創(chuàng)建該頁的實(shí)例之前對其進(jìn)行編譯。  
  12. 11. 引發(fā) PostMapRequestHandler 事件。  
  13. 12. 引發(fā) AcquireRequestState 事件。  
  14. 13. 引發(fā) PostAcquireRequestState 事件。  
  15. 14. 引發(fā) PreRequestHandlerExecute 事件。  
  16. 15. 為該請求調(diào)用合適的 IHttpHandler 類的 ProcessRequest 方法(或異步版 IHttpAsyncHandler.BeginProcessRequest)。 例如,如果該請求針對某頁,則當(dāng)前的頁實(shí)例將處理該請求。   
  17. 16. 引發(fā) PostRequestHandlerExecute 事件。  
  18. 17. 引發(fā) ReleaseRequestState 事件。  
  19. 18. 引發(fā) PostReleaseRequestState 事件。  
  20. 19. 如果定義了 Filter 屬性,則執(zhí)行響應(yīng)篩選。  
  21. 20. 引發(fā) UpdateRequestCache 事件。  
  22. 21. 引發(fā) PostUpdateRequestCache 事件。  
  23. 22. 引發(fā) EndRequest 事件。  
  24. 23. 引發(fā) PreSendRequestHeaders 事件。  
  25. 24. 引發(fā) PreSendRequestContent 事件。  

圖片中還反映了ASP.NET的三種主要的參與者:

1. HttpModule;2. HttpHandlerFactory;3. HttpHandler

有沒有有想過:這三種參與者中,每種有多少個參與對象呢?

為了清楚地回答這個問題,我準(zhǔn)備了下面的表格:

為什么要引入HttpHandlerFactory呢? 請看我的博客 細(xì)說 HttpHandler 的映射過程,今天就不重復(fù)這塊內(nèi)容了。

除開HttpHandlerFactory,我們可以發(fā)現(xiàn):在ASP.NET管線中,HttpHandler應(yīng)該只有一個,而HttpModule是可選的。

進(jìn)而,我們是不是可以這樣理解:HttpHandler才是處理請求的主角(不可缺少),HttpModule是配角(可以沒有)?

#p#

理解HttpApplication

前面我們一直在說ASP.NET管線,那么,誰在控制管線過程?

答案是:HttpApplication對象。

1. HttpApplication細(xì)分它的處理過程,在不同階段引發(fā)不同的事件,使得HttpModule通過訂閱事件的方式加入到請求的處理過程中。

2. 在請求的處理過程中,HttpApplication對象主要扮演著控制處理流程的推進(jìn)作用。

3. HttpApplication會在固定的階段獲取一個IHttpHandler實(shí)例,然后將請求的響應(yīng)過程交給具體的IHttpHandler來實(shí)現(xiàn)。

HttpApplication如何產(chǎn)生,如何工作?

1. HttpApplication對象會被重用,當(dāng)HttpRuntime不能從HttpApplicationFactory獲取空閑的實(shí)例時,才會創(chuàng)建。

2. HttpRuntime會將每個請求交給一個HttpApplication對象來處理。

3. HttpApplication對象在初始化時負(fù)責(zé)加載全部的HttpModule。

4. 每個HttpApplication對象會控制屬于它的管線過程(前面已解釋)。

HttpApplication是個非常重要的類型,它的許多功能都屬于框架的基礎(chǔ)部分,不需要我們調(diào)用,因此,我們平時不會用到它。

我不想讓博客走題,下面來看看今天的主角吧。

#p#

理解HttpHandler

前面說到HttpRuntime會將請求交給HttpApplication來處理,此時你有沒有想過這樣一個問題:為什么HttpApplication不直接處理請求,而是要再交給一個HttpHandler對象來處理呢?

答案是:每個請求的內(nèi)容可能并不相同,它們存在多樣性,因此ASP.NET采用了抽象工廠模式來處理這些請求。 ASP.NET在web.config的架構(gòu)中,允許我們指定某些請求映射到一個HttpHandlerFactory,例如:

  1. <!--適用于IIS6的配置-->  
  2. <system.web>  
  3.     <httpHandlers>  
  4.         <add path="*.cspx" verb="*" type="MyMVC.AjaxHandlerFactory, MyMVC" validate="true" />  
  5.         <add path="*.aspx" verb="*" type="MyMVC.MvcPageHandlerFactory, MyMVC" validate="true" />  
  6.         <add path="/mvc/*" verb="*" type="MyMVC.MvcPageHandlerFactory, MyMVC" validate="true" />  
  7.     </httpHandlers>  
  8. </system.web>  
  9.  
  10. <!--適用于IIS7的配置(集成模式)-->  
  11. <system.webServer>  
  12.     <handlers>  
  13.         <add name="AjaxHandlerFactory" verb="*" path="*.cspx" type="MyMVC.AjaxHandlerFactory, MyMVC" preCondition="integratedMode" />  
  14.         <add name="MvcPageHandlerFactory" verb="*" path="*.aspx" type="MyMVC.MvcPageHandlerFactory, MyMVC" preCondition="integratedMode" />  
  15.         <add name="MvcPageHandlerFactory2" verb="*" path="/mvc/*" type="MyMVC.MvcPageHandlerFactory, MyMVC" preCondition="integratedMode" />  
  16.     </handlers>  
  17. </system.webServer>  

當(dāng)某個請求與一個規(guī)則匹配后,ASP.NET會調(diào)用匹配的HttpHandlerFactory的GetHandler方法來獲取一個HttpHandler實(shí)例, 最后由一個HttpHandler實(shí)例來處理當(dāng)前請求。

HttpApplication是如何將請求交給HttpHandler實(shí)例來處理的呢?

為了理解這個過程,我們要來看一下IHttpHandler接口的定義:

  1. // 這個接口用于同步調(diào)用  
  2. // 異步版本的接口用法請參考:http://www.cnblogs.com/fish-li/archive/2011/11/20/2256385.html  
  3.  
  4. public interface IHttpHandler  
  5. {  
  6.     // 獲取一個值,該值指示其他請求是否可以使用 IHttpHandler 實(shí)例。  
  7.     bool IsReusable { get; }  
  8.  
  9.     // 通過實(shí)現(xiàn) IHttpHandler 接口的自定義 HttpHandler 啟用 HTTP Web 請求的處理。  
  10.     void ProcessRequest(HttpContext context);  
  11. }  

HttpApplication在將某個請求交給HttpHandler實(shí)例來處理時,是通過接口來調(diào)用的(ProcessRequest方法)。

與HttpHandler的相關(guān)話題:

1. 異步 HttpHandler:細(xì)說ASP.NET的各種異步操作

2. 如何重用HttpHandler:細(xì)說 HttpHandler 的映射過程

HttpHanlder的典型應(yīng)用

  1. <%@ WebHandler Language="C#" Class="Login" %>  
  2. using System;  
  3. using System.Web;  
  4. public class Login : IHttpHandler {        
  5.     public void ProcessRequest (HttpContext context) {  
  6.         context.Response.ContentType = "text/plain";  
  7.  
  8.         string username = context.Request.Form["name"];  
  9.         string password = context.Request.Form["password"];  
  10.  
  11.         if( password == "aaaa" ) {  
  12.             System.Web.Security.FormsAuthentication.SetAuthCookie(username, false);  
  13.             context.Response.Write("OK");  
  14.         }  
  15.         else {  
  16.             context.Response.Write("用戶名或密碼不正確。");  
  17.         }  
  18.     }  

通常我去這樣創(chuàng)建一個ashx文件(HttpHanlder)響應(yīng)某種特殊的請求。

所以,我們應(yīng)該這樣理解HttpHanlder:一個HttpHanlder用于響應(yīng)一類特定的請求。

我們經(jīng)常用到的HttpHanlder有哪些?

  1. 1. aspx頁面。  
  2. 2. asmx服務(wù)文件。  
  3. 3. ashx文件(一般處理程序)。  
  4. 4. 實(shí)現(xiàn)IHttpHandler接口的自定義類型。  

我們通常使用HttpHanlder做什么?

 

注意觀察表格中實(shí)現(xiàn)目標(biāo),我們可以得到一個結(jié)論:使用HttpHanlder的目的是生成響應(yīng)結(jié)果。

#p#

理解HttpModule

設(shè)計(jì)HttpHanlder的目的很明確:生成響應(yīng)結(jié)果。

那么,設(shè)計(jì)HttpModule又是為什么呢?

前面說過,一個HttpHanlder用于處理一類特定的請求,每個aspx, ashx都可以認(rèn)為是一類請求。有時候我們發(fā)現(xiàn)所有頁面可能都需要某些相同的檢查功能(如身份檢查),假如只能使用HttpHanlder,那我們就要讓所有頁面都去調(diào)用那些相同的檢查功能。誰愿意做這些重復(fù)的事情?或許有些人會回答,可以自己實(shí)現(xiàn)一個基類,把檢查功能放在基類中去調(diào)用。然而,這種做法只能解決重復(fù)調(diào)用問題,它會讓代碼失去靈活性(擴(kuò)展性),試想一下:如果需要再加入新的檢查功能,或者用新的檢查方法替換原有的檢查邏輯時怎么辦?只能是修改基類了吧?

設(shè)計(jì)HttpModule的目的正是為了提供一個靈活的方法解決這種功能重用問題。它采用事件(觀察者)的設(shè)計(jì)模式,將某些HttpHanlder都需要的功能抽取出來,形成不同的觀察者類型,這些觀察者類型可以編譯成類庫形式,供多個網(wǎng)站項(xiàng)目共用。為了讓ASP.NET管線更靈活,ASP.NET允許我們在web.config中自由配置需要的HttpModule,例如:

  1. <!--適用于IIS6的配置-->  
  2. <system.web>  
  3.     <httpModules>  
  4.         <add name="SetOutputCacheModule" type="MyMVC.SetOutputCacheModule, MyMVC"/>  
  5.     </httpModules>  
  6. </system.web>  
  7.  
  8. <!--適用于IIS7的配置(集成模式)-->  
  9. <system.webServer>  
  10.     <modules>  
  11.         <add name="SetOutputCacheModule" type="MyMVC.SetOutputCacheModule, MyMVC" preCondition="integratedMode" />  
  12.     </modules>  
  13. </system.webServer>  

配置只是告訴ASP.NET:這些HttpModule需要運(yùn)行起來。有沒有想過這些HttpModule到底是如何進(jìn)入管線運(yùn)行起來的呢?前面我只是說了HttpModule會訂閱這些事件,那么事件又是在哪里訂閱的呢?還是來看一下IHttpModule接口的定義吧:

  1. // 這個接口用于同步調(diào)用  
  2. // 異步用法請參考:http://www.cnblogs.com/fish-li/archive/2011/11/20/2256385.html  
  3.  
  4. public interface IHttpModule  
  5. {  
  6.     //  初始化模塊,并使其為處理請求做好準(zhǔn)備。  
  7.     void Init(HttpApplication app);  
  8.  
  9.     void Dispose();  
  10. }  

注意這個關(guān)鍵的Init方法,它傳入一個HttpApplication類型的參數(shù),有了HttpApplication對象,HttpModule就可以訂閱HttpApplication的所有事件了。請看下面的示例代碼:

  1. public class TestModule : IHttpModule  
  2. {  
  3.     public void Dispose() {}  
  4.  
  5.     public void Init(HttpApplication app)  
  6.     {  
  7.         app.PostAcquireRequestState += new EventHandler(app_PostAcquireRequestState);  
  8.         app.PreRequestHandlerExecute += new EventHandler(app_PreRequestHandlerExecute);  
  9.     }  
  10.     void app_PreRequestHandlerExecute(object sender, EventArgs e)  
  11.     {  
  12.         throw new NotImplementedException();  
  13.     }  
  14.     void app_PostAcquireRequestState(object sender, EventArgs e)  
  15.     {  
  16.         throw new NotImplementedException();  
  17.     }  
  18. }  

HttpModule的典型應(yīng)用

  1. public class SetOutputCacheModule : IHttpModule  
  2. {  
  3.     public void Init(HttpApplication app)  
  4.     {  
  5.         app.PreRequestHandlerExecute += new EventHandler(app_PreRequestHandlerExecute);  
  6.     }  
  7.  
  8.     void app_PreRequestHandlerExecute(object sender, EventArgs e)  
  9.     {  
  10.         HttpApplication app = (HttpApplication)sender;  
  11.         Dictionary<string, OutputCacheSetting> settings = ConfigManager.Settings;  
  12.         if( settings == null )  
  13.             throw new ConfigurationErrorsException("SetOutputCacheModule加載配置文件失敗。");  
  14.  
  15.         // 實(shí)現(xiàn)方法:  
  16.         // 查找配置參數(shù),如果找到匹配的請求,就設(shè)置OutputCache  
  17.         OutputCacheSetting setting = null;  
  18.         if( settings.TryGetValue(app.Request.FilePath, out setting) ) {  
  19.             setting.SetResponseCache(app.Context);  
  20.         }  
  21.     }  

這個Module用于給一些在配置文件中指出要緩存的請求設(shè)置輸出緩存,示例代碼已在上篇博客 不修改代碼就能優(yōu)化ASP.NET網(wǎng)站性能的一些方法 介紹過了。其實(shí)設(shè)置輸出緩存的最根本手段還是調(diào)用Response.Cache的一些公開方法,修改輸出響應(yīng)頭。

我們用HttpModule做什么事情?

1. 修改某些請求(例如前面的示例修改了響應(yīng)頭)。

2. 檢查檢查請求(例如身份認(rèn)證檢查)。

HttpModule能處理哪些請求呢?

1. 默認(rèn)是全部進(jìn)入ASP.NET的請求。

2. 如果只需要處理部分請求,那么請自行判斷(參考前面的示例)。

#p#

三大對象的總結(jié)

前面我分別介紹了HttpApplication,HttpHanlder和HttpModule,這里再把三者的關(guān)系重新梳理一遍。

在請求的處理過程中,HttpApplication對象主要扮演著控制管線處理流程的作用,它負(fù)責(zé)推進(jìn)整個處理流程,除了在不同階段引發(fā)不同的事件外(供HttpModule使用),HttpApplication對象還會根據(jù)當(dāng)前請求尋找一個合適的IHttpApplicationFactory實(shí)例,并最終得到一個IHttpHandler的實(shí)例用于處理請求。

設(shè)計(jì)這三種類型的目的在于:

1. HttpApplication控制處理流程,在不同階段引發(fā)不同的事件。

2. 由于請求的多樣性,每個請求會由一個HttpHandler對象來處理。

3. 對于一些通用性的功能,尤其是與響應(yīng)內(nèi)容無關(guān)的,設(shè)計(jì)成HttpModule是最合適的。

案例演示

Q:我有一些html文件,需要做身份認(rèn)證檢查(判斷Session),我該如何實(shí)現(xiàn)?

想好了就來看看我的解決方案:

  1. /// <summary>  
  2. /// 用于響應(yīng)HTML文件的處理器  
  3. /// </summary>  
  4. public class HtmlHttpHandler : IHttpHandler, IRequiresSessionState, IReadOnlySessionState   
  5. {  
  6.     public void ProcessRequest(HttpContext context)  
  7.     {  
  8.         // 獲取要請求的文件名  
  9.         string filePath = context.Server.MapPath(context.Request.FilePath);  
  10.  
  11.         // 用Fiddler查看響應(yīng)頭,如果看到有這個頭,就表示是由這段代碼處理的。  
  12.         context.Response.AddHeader("SeesionExist", (context.Session != null ? "yes""no"));  
  13.  
  14.         // 在這里,你可以訪問context.Session  
  15.  
  16.         // 設(shè)置響應(yīng)內(nèi)容標(biāo)頭  
  17.         context.Response.ContentType = "text/html";  
  18.  
  19.         // 輸出文件內(nèi)容  
  20.         context.Response.TransmitFile(filePath);  
  21.     }  

在這個案例中我為什么要選擇HttpHandler呢?

1. 我需要 響應(yīng)一類請求(所有的HTML文件)。

2. 請求要求支持 Session

所以我最終選擇了HttpHandler 。

Q:我需要壓縮所有的ASP.NET請求的響應(yīng)結(jié)果,該怎么實(shí)現(xiàn)?

想好了就來看看我的解決方案:

  1. /// <summary>  
  2. /// 為請求支持gzip壓縮輸出的DEMO  
  3. /// </summary>  
  4. public class GzipModule : IHttpModule  
  5. {  
  6.     public void Init(HttpApplication app)  
  7.     {  
  8.         app.BeginRequest += new EventHandler(app_BeginRequest);  
  9.     }  
  10.  
  11.     void app_BeginRequest(object sender, EventArgs e)  
  12.     {  
  13.         HttpApplication app = (HttpApplication)sender;  
  14.  
  15.         // 判斷瀏覽器是否支持GZIP壓縮  
  16.         string flag = app.Request.Headers["Accept-Encoding"];  
  17.         ifstring.IsNullOrEmpty(flag) == false && flag.ToLower().IndexOf("gzip") >= 0 ) {  
  18.             // 設(shè)置GZIP壓縮  
  19.             app.Response.Filter = new GZipStream(app.Response.Filter, CompressionMode.Compress);  
  20.             app.Response.AppendHeader("Content-Encoding""gzip");  
  21.         }  
  22.     }  

在這個案例中我為什么要選擇HttpModule呢?

原因只有一個:我需要 設(shè)置所有請求。

所以我最終選擇了HttpModule 。

#p#

如何選擇?

在結(jié)束這篇博客之前,再問問各位讀者:現(xiàn)在知道何時選擇HttpHandler還是HttpModule了嗎?

如果還沒有看明白,那我就最后告訴你一個識別方法:

1. 如果要響應(yīng)一類請求,那么就選擇HttpHandler。

2. 如果要修改或者檢查所有請求(總之就是不生成響應(yīng)結(jié)果),那就選擇HttpModule。

最后給各位留下一個題目,下面這些ASP.NET提供的功能,它們是采用了哪個方式實(shí)現(xiàn)的?

1. Session

2. 身份認(rèn)證

3. URL授權(quán)檢查

4. 通過trace.axd查看跟蹤信息

5. OutputCache

6. 禁止下載config文件

7. 禁止查看下載源代碼文件

注意:本文的主題是:選擇HttpHandler還是HttpModule,所以請不要扯遠(yuǎn)了。

原文鏈接:http://www.cnblogs.com/fish-li/archive/2013/01/04/2844908.html

責(zé)任編輯:張偉 來源: 博客園
相關(guān)推薦

2013-03-20 10:43:15

HttpHandlerHttpModule

2009-07-20 16:12:21

ASP.NET Fra

2013-01-15 10:50:42

2012-08-16 09:38:38

ASP.NET

2009-07-27 15:48:43

2013-05-30 13:30:00

代碼效率程序員

2023-11-09 09:13:48

GraphQLAPI 架構(gòu)

2013-07-04 14:54:24

Android

2009-08-10 14:55:43

ASP.NET htt

2009-06-19 13:31:39

GETPOSTAjax

2011-04-13 16:59:41

HTTPASP.NET

2020-07-01 14:05:21

麥肯錫機(jī)器人從業(yè)者

2013-06-08 09:05:06

2019-07-05 15:45:39

UbuntuFedoraLinux

2011-04-13 16:49:26

HTTPASP.NET

2011-04-13 16:35:47

HTTPASP.NET

2015-08-19 10:13:53

DaasVDI

2023-03-11 22:45:15

物聯(lián)網(wǎng)供電技術(shù)以太網(wǎng)

2012-06-14 10:06:43

創(chuàng)業(yè)動態(tài)語言靜態(tài)語言

2013-01-08 10:41:38

vSphere 5.1Windows Ser
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 欧美精品三区 | 国产精品久久久久aaaa九色 | 羞羞视频网站免费观看 | 精品欧美一区二区三区免费观看 | 亚洲午夜精品视频 | 国产一级视频在线观看 | 国产亚洲精品综合一区 | 一级毛片免费看 | 成人午夜在线 | 国产一区三区视频 | 99在线免费观看视频 | 国产黄色一级片 | 日韩国产在线 | 国产美女自拍视频 | 亚洲欧美一区二区三区1000 | 超碰人人插| 理伦毛片 | 超碰国产在线 | 毛片免费视频 | 黄色国产视频 | 久久草视频 | 中文字幕久久久 | 国产精品一区二区久久 | 九色视频网 | 国产一区二区三区免费 | 免费精品视频 | 在线观看亚洲精品视频 | com.色.www在线观看 | 1区2区视频 | 亚洲一二三区在线观看 | 在线国产视频 | 欧美激情免费在线 | 国产玖玖| 涩涩视频网站在线观看 | 中文字幕不卡视频在线观看 | 中文字幕视频免费 | 日韩在线国产 | 亚洲毛片网站 | 日本在线视频一区二区 | 国产成人精品综合 | 综合久久一区 |