程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> httpHandlers與Http處理程序,httphandlers處理

httpHandlers與Http處理程序,httphandlers處理

編輯:關於.NET

httpHandlers與Http處理程序,httphandlers處理


ASP.NET HTTP 處理程序是響應對 ASP.NET Web 應用程序的請求而運行的過程(通常稱為"終結點")。最常用的處理程序是處理 .aspx 文件的 ASP.NET 頁處理程序。用戶請求 .aspx 文件時,頁通過頁處理程序來處理請求。

ASP.NET 頁處理程序僅僅是一種類型的處理程序。ASP.NET 還包括其他幾種內置的處理程序,例如用於 .asmx 文件的 Web 服務處理程序。

如果您需要進行特殊處理(可以在應用程序中使用文件擴展名進行標識),可以創建自定義 HTTP 處理程序。例如,下面的方案就很好地利用了自定義 HTTP 處理程序:

  • RSS 源   若要為站點創建 RSS 源,可以創建一個可發出 RSS 格式 XML 的處理程序。然後將您應用程序中的 .rss 擴展名(舉例)綁定到此自定義處理程序。當用戶向站點發送以 .rss 結尾的請求時,ASP.NET 將調用您的處理程序來處理請求。
  • 圖像服務器   如果希望 Web 應用程序能夠提供不同大小的圖像,可以編寫一個自定義處理程序來調整圖像大小,然後將調整後的圖像作為處理程序的響應返回給用戶。

HTTP 處理程序可以訪問應用程序上下文,包括請求用戶的標識(如果已知)、應用程序狀態和會話信息等。當請求 HTTP 處理程序時,ASP.NET 將調用相應處理程序上的 ProcessRequest 方法。處理程序的 ProcessRequest 方法創建一個響應,此響應隨後發送回請求浏覽器。就像任何頁請求那樣,響應將途經訂閱了處理程序運行後所發生事件的所有 HTTP 模塊。有關處理 Web 服務器請求的更多信息,請參見 ASP.NET 應用程序生命周期概述。

HTTP 處理程序可以是同步的也可以是異步的。同步處理程序在完成對為其調用該處理程序的 HTTP 請求的處理後才會返回。異步處理程序運行進程的行為與向用戶發送響應無關。當您需要啟動一個可能耗費很長時間的應用程序進程,而用戶又無需等候進程完成以便從服務器獲取響應時,異步處理程序非常有用。

ASP.NET 中的內置 HTTP 處理程序

ASP.NET 根據文件擴展名將 HTTP 請求映射到 HTTP 處理程序。每個 HTTP 處理程序都能夠處理應用程序中的單個 HTTP URL 或 URL 擴展名組。ASP.NET 包括幾種內置的 HTTP 處理程序,如下表所列。

處理程序

說明

ASP.NET 頁處理程序 (*.aspx)

用於所有 ASP.NET 頁的默認 HTTP 處理程序。

Web 服務處理程序 (*.asmx)

用於使用 ASP.NET 創建的 Web 服務頁的默認 HTTP 處理程序。

ASP.NET 用戶控件處理程序 (*.ascx)

用於所有 ASP.NET 用戶控件頁的默認 HTTP 處理程序。

跟蹤處理程序 (trace.axd)

顯示當前頁跟蹤信息的處理程序。有關詳細信息,請參見如何:使用跟蹤查看器查看 ASP.NET 跟蹤信息。

如上面配置所示,.NET Framework配置中添加的Handler,實際後面還跟了一堆,不過都是同一種HttpFrobiddenHandler

創建自定義 HTTP 處理程序

若要創建一個自定義 HTTP 處理程序,可以創建一個可實現 IHttpHandler 接口的類以創建同步處理程序,或者創建一個可實現 IHttpAsyncHandler的類以創建異步處理程序。兩種處理程序接口都要求您實現 IsReusable 屬性和 ProcessRequest 方法。IsReusable 屬性指定 IHttpHandlerFactory對象(實際調用適當處理程序的對象)是否可以將您的處理程序放置在池中,並且重新使用它們以提高性能,或是否在每次需要處理程序時都必須創建新實例。ProcessRequest 方法負責實際處理單個 HTTP 請求。

創建文件擴展名

創建一個類文件作為您的 HTTP 處理程序時,可以讓您的處理程序響應尚未在 IIS 和 ASP.NET 中映射的任何文件擴展名。例如,如果您在創建用於生成 RSS 源的 HTTP 處理程序,則可以將處理程序映射到擴展名 .rss。為了讓 ASP.NET 知道哪個處理程序將用於您的自定義文件擴展名,必須在 IIS 中將處理程序類文件的擴展名映射到 ASP.NET,並且在您的應用程序中將該擴展名映射到您的自定義處理程序。

默認情況下,ASP.NET 為自定義 HTTP 處理程序映射文件擴展名 .ashx 的方式與將擴展名 .aspx 映射到 ASP.NET 頁處理程序的方式相同。因此,如果您創建具有文件擴展名 .ashx 的 HTTP 處理程序類,該處理程序將自動注冊到 IIS 和 ASP.NET。

如果想要為您的處理程序創建自定義文件擴展名,則必須顯式將該擴展名注冊到 IIS 和 ASP.NET。不使用文件擴展名 .ashx 的好處是您的處理程序隨後可以重新用於其他擴展名映射。例如,在某個應用程序中,您的自定義處理程序可能響應以 .rss 結尾的請求,而在另一個應用程序中,您的自定義處理程序可能響應以 .feed 結尾的請求。再舉一例,您的處理程序可能映射到同一應用程序中的兩個文件擴展名,但可能基於擴展名創建兩個不同的響應。

下面通過一個例子來演示httpHandler的建立,注冊以及效果

在App_Code中添加類ApkHandler實現接口IHttpHandler

 

namespace FastDoge.Study
{
    public class ApkHandler : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            HttpRequest Request = context.Request;
            HttpResponse Response = context.Response;
            // This handler is called whenever a file ending 
            // in .sample is requested. A file with that extension
            // does not need to exist.
            Response.Write("<html>");
            Response.Write("<body>");
            Response.Write("<h1>Hello from a synchronous custom HTTP handler.</h1>");
            Response.Write("</body>");
            Response.Write("</html>");
        }
        public bool IsReusable
        {
            // To enable pooling, return true here.
            // This keeps the handler in memory.
            get { return false; }
        }
    }
}

 

 

 

接著到Web.config中注冊Hanler,這裡對於兩個不同版本的IIS也會有出入

在 IIS 6.0 和 IIS 7.0 經典模式下運行的Web.config添加以下配置

    <httpHandlers>
      <add verb="*" path="*.apk" 
        type="FastDoge.Study.ApkHandler" />
    </httpHandlers>

 

verb指定謂詞列表可以是逗號分隔的 HTTP 謂詞列表(例如,"GET, PUT, POST"),也可以是開始腳本映射(如星號 [*] 通配符)。

path:指定路徑屬性可以包含單個 URL 路徑或簡單的通配符字符串(如 *.aspx)。

type:指定逗號分隔的類/程序集組合。ASP.NET 首先在應用程序的專用 \bin 目錄中搜索程序集 DLL,然後在系統程序集緩存中搜索程序集 DLL。

IIS7集成模式配置如下

  <system.webServer>
    <handlers>
      <add name="ApkHandler" verb="*"
        path="*.apk"
        type="FastDoge.Study.ApkHandler"
        resourceType="Unspecified" />
    </handlers>
  </system.webServer>

 

在運行後在浏覽器中輸入一個以apk為後綴的url

在MSDN中提到的可以在IIS中通過圖形界面注冊,這裡就不嘗試了,可參考https://msdn.microsoft.com/zh-cn/library/bb515343(v=vs.100).aspx。當然如果不在配置文件中添加,要是在HttpModule中指定,要與HttpModule耦合在一起的話就如上篇所說調用HttpContext.RemapHandler方法,如在上篇提到的MyModule類中作以下改動

        private void Application_BeginRequest(Object source,
        EventArgs e)
        {
            HttpApplication application = (HttpApplication)source;
            HttpContext context = application.Context;
            context.Response.Write("<h1><font color=red>" +
                "HelloWorldModule: Beginning of Request" +
                "</font></h1><hr>");

            string filePath = context.Request.FilePath;
            string fileExtension =
                VirtualPathUtility.GetExtension(filePath);
            if (fileExtension.Equals(".apk", StringComparison.InvariantCultureIgnoreCase) &&
                 context.Request.HttpMethod.Equals("GET"))
            {
                context.RemapHandler(new ApkHandler());
            }
        }

 

去掉Web.config的配置,訪問以上URL有同樣的效果。

   

異步 HTTP 處理程序

利用異步 HTTP 處理程序可以啟動一個外部進程(例如對遠程服務器的方法調用),然後繼續處理程序的處理工作,而無需等待外部進程結束。在異步 HTTP 處理程序的處理期間,ASP.NET 將通常用於外部進程的線程放回線程池中,直到處理程序收到來自外部進程的回調。這樣可以避免阻止線程,並大幅改善了性能,因為一次所能執行的線程數量是有限的。如果許多用戶都在請求依賴於外部進程的同步 HTTP 處理程序,那麼操作系統可能很快就會用完所有線程,因為大量線程被阻止,正在等待外部進程。

創建異步處理程序時,除了實現 IHttpAsyncHandler 接口,還必須實現 BeginProcessRequest 以啟動異步調用來處理單個 HTTP 請求。還必須實現 EndProcessRequest 方法,以便在進程結束時運行清理代碼。

下面則定義了一個AsyncApkHandler的異步處理程序,在BeginProcessRequest時調用一個AsynchOperation,該類實現IAsyncResult接口,需要異步操作的代碼在方法StartAsyncWork()中調用

 

namespace FastDoge.Study
{
    public class AsyncApkHandler : IHttpAsyncHandler
    {
        public bool IsReusable { get { return false; } }

  
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
        {
            context.Response.Write("<p>Begin IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + " " + DateTime.Now + "  " + Thread.CurrentThread.ManagedThreadId + "</p>\r\n");
            AsynchOperation asynch = new AsynchOperation(cb, context, extraData);
            asynch.StartAsyncWork();
            return asynch;
        }

        public void EndProcessRequest(IAsyncResult result)
        {
            if (result is AsynchOperation)
            {
                (result as AsynchOperation).Context.Response.Write("<p>End IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + "  "+DateTime.Now+"  " + Thread.CurrentThread.ManagedThreadId + "</p>\r\n");
            }
        }

        public void ProcessRequest(HttpContext context)
        {
            throw new InvalidOperationException();
        }
    }

    class AsynchOperation : IAsyncResult
    {
        private bool _completed;
        private Object _state;
        private AsyncCallback _callback;
        private HttpContext _context;

        bool IAsyncResult.IsCompleted { get { return _completed; } }
        WaitHandle IAsyncResult.AsyncWaitHandle { get { return null; } }
        Object IAsyncResult.AsyncState { get { return _state; } }
        bool IAsyncResult.CompletedSynchronously { get { return false; } }

        public HttpContext Context
        {
            get
            {
                return _context;
            }
        }

        public AsynchOperation(AsyncCallback callback, HttpContext context, Object state)
        {
            _callback = callback;
            _context = context;
            _state = state;
            _completed = false;
        }

        public void StartAsyncWork()
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncTask), null);
        }

        private void StartAsyncTask(Object workItemState)
        {
            Thread.Sleep(3000);
            _context.Response.Write("<p>Completion IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + "  " + DateTime.Now + " " + Thread.CurrentThread.ManagedThreadId + "</p>\r\n");

            _context.Response.Write("Hello World from Async Handler!");
            _completed = true;
            _callback(this);
        }
    }
}

 

 

配置方式如之前的方式。效果如下

   

自定義 IHttpHandlerFactory 類

IHttpHandlerFactory 類接收請求並負責向相應的 HTTP 處理程序轉發請求。您可以通過創建一個實現了 IHttpHandlerFactory 接口的類來創建自定義 HTTP 處理程序工廠。創建自定義處理程序工廠可以更好地控制對 HTTP 請求的處理,因為這樣可以基於運行時條件創建不同的處理程序。例如,使用自定義 HTTP 處理程序工廠,可以在 HTTP 請求方法為 PUT 時為某個文件類型實例化一個 HTTP 處理程序,而在該方法為 GET 時實例化另一個 HTTP 處理程序。又例如,通過使用 HTTP 處理程序工廠,可以創建有限數量的 HTTP 處理程序對象,來訪問諸如數據庫連接等昂貴或有限的資源。然後,可以在以後的請求中重用這些處理程序對象。

IHttpHandlerFactory 有兩個方法

IHttpHandler GetHandler:返回實現 System.Web.IHttpHandler 接口的類的實例;

void ReleaseHandler:使工廠可以重用現有的處理程序實例。

下面則定義個ApkHanlderFactory,同時在ApkHandler 輸出的內容上有稍作修改(輸出當前HttpHandler的HashCode)

 

namespace FastDoge.Study
{
    public class ApkHanlderFactory : IHttpHandlerFactory
    {
        private ApkHandler _cacheHandler;

        private ApkHandler CacheHandler
        {
            get
            {
                if (_cacheHandler == null)
                {
                    _cacheHandler = new ApkHandler();
                }
                return _cacheHandler;
            }
        }

        public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
        {
            if (context.Request.QueryString.AllKeys.Contains("IsCache") &&
                context.Request["IsCache"].ToLower().Equals("true", StringComparison.InvariantCultureIgnoreCase))
            {
                return CacheHandler;
            }
            return new ApkHandler();
        }

        public void ReleaseHandler(IHttpHandler handler)
        {
            
        }
    }
}

 

 

配置文件方面與注冊IHttpHandler基本一致,只是type特性中填寫的是實現IHttpHandlerFactory接口的類名,但是在Module中通過編碼的形式指定的方式暫時沒找到,估計需要看源碼了。

請求URL如下URL時,響應的html內容一直不變

如果去除IsCache參數時,內容則每次都在變化。

   

   

參考內容

HTTP 處理程序介紹

來自 <https://msdn.microsoft.com/zh-cn/library/ms227675(v=vs.100).aspx>

HTTP 處理程序和 HTTP 模塊概述

來自 <https://msdn.microsoft.com/zh-cn/library/bb398986(v=vs.100).aspx>

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved