Asp.Net高級知識回顧_HttpHandler

1、概述:html

其實每一個.aspx頁面都是一個HttpHandler,由於System.Web.UI.Page類實現了IHttpHandler接口。通常狀況下,響應客戶端請求的都是.aspx頁面,這時候System.Web.UI.Page類能夠做出合適的處理。但有時候響應給客戶端的不必定就是.aspx頁面,有多是XML或者圖像等,這個時候就須要自定義HttpHandler進行處理。web

經常使用的HttpHandler處理有構造縮略圖、圖片加水印。通常在網站中,好比一個購物網站的商品列表裏,顯示的商品圖片都是通過縮略處理。你們能夠想象到,若是直接把原圖返回到客戶端顯示,網絡流量是如此巨大,這樣會嚴重影響頁面顯示速度。一樣,不少網站上的圖像資源都是原創的,爲了保證版權,防止不法盜用,都會在圖片返回到客戶端以前對圖片進行處理,加上數字水印標記。爲圖片資源加上水印,能夠防止原創圖片被非法盜用,並且使用編程方式添加能夠在不破壞原圖的狀況下對圖片進行處理。編程

HttpHandler與HttpModule區別:緩存

二者的區別:服務器

a. 前後次序:
數據先通過HttpModule,再通過HttpHandler,而後又返回到HttpModule。注意,Module要判斷響應的是哪一個事件,有些事件是在Handler以前執行,有些是在Handler以後執行。網絡

b.對請求的處理:
HttpModule不管客戶端請求的是什麼文件,它都會對請求進行攔截處理,例如.aspx,.rar,.html,.jpg等等的請求。HttpHandler只有在ASP.NET註冊過的文件類型(例如aspx,asmx等等)纔會調用它。異步

c.HttpHandler是請求的最終處理中心,按照請求生成響應的內容。HttpModule對請求進行預處理,如驗證、修改、過濾等等,同時也能夠對響應進行處理。性能

2、IHttpHandler網站

IHttpHandler接口:定義ASP.NET爲使用自定義Http處理程序同步處理Http Web請求而實現的協定。Http處理程序是實現了System.Web.IHttpHandler接口的.NET組件,接口是一種規範,所以任何實現了IHttpHandler接口的類均可以用於處理輸入的Http請求。ui

Http處理程序可分爲同步處理程序、異步處理程序。同步處理程序必須繼承IHttpHandler接口,異步處理程序必須繼承IHttpAsyncHandler接口。

public interface IHttpHandler
    {
        // 摘要:
        // 獲取一個值,該值指示其餘請求是否可使用System.Web.IHttpHandler實例。
        // 返回結果:
        // 若是System.Web.IHttpHandler實例可再次使用,則爲true;不然爲false。
        bool IsReusable { get; }

        // 摘要:
        // 經過實現System.Web.IHttpHandler接口的自定義HttpHandler啓用HTTP Web請求的處理。
        // 參數:
        // context:
        //  System.Web.HttpContext 對象,它提供對用於爲 HTTP 請求提供服務的內部服務器對象(如 Request、Response、Session、和Server)的引用。
        void ProcessRequest(HttpContext context);
    }
1.0 IsReusable
//IsReusable屬性指定IHttpHandlerFactory對象(實際調用適當處理程序的對象)是否能夠將處理程序放置在由CLR會維護的一個對象池中,而且從新使用它們以提升性能,或是否在每次須要處理程序時都必須建立新實例。若是IHttpHandler實例可再次使用,則爲true,不然爲false。
//Page類上的IsReusable屬性返回false,表示須要該Http請求的新實例來服務一個頁面請求。一般咱們使它在全部狀況下都返回false,並根據請求負荷的不一樣而要求它作一些有意義的處理。那些不依賴於context.Request對象,也沒有成員變量,被用做篩選特殊請求的簡單屏障的處理程序能夠將IsReusable設置爲true,以節省一些系統資源。
2.0 ProcessRequest
//顧名思義,ProcessRequest就是請求響應,是Http請求的最終處理方法。一個Http請求都是最終交給一個HttpHandler容器中的ProcessRequest方法來處理。方法中應該放置咱們處理請求的主要代碼。

在ProcessRequest方法中,須要一個HttpContext類型的參數,這個參數也稱爲上下文。它封裝有關個別 Http請求的全部Http特定的信息。在HttpContext對象中能夠得到用於爲Http請求提供服務的內部服務器對象(如Request、Response和Server)的引用。當客戶端發送某個Http請求,咱們能夠經過HttpContext進行截獲,查看裏面所包含的請求信息,能夠進行一系列的操做。

下面以圖片添加數字水印例子簡述ProcessRequest方法的用法:

首先建立HttpHandler處理類。在項目中添加一個實現了IHttpHandler接口的類,這裏咱們把HttpHandler處理類命名爲「CoverHandler」。代碼以下所示:

using System;
using System.Web;
public class CoverHandler: IHttpHandler { 
 //須要繼承IHttpHandler接口
      public CoverHandler()
    {
    }
    //水印圖片路徑
private const string WATERMARK_URL = "~/Image/watermark.bmp";
//默認圖片路徑
private const string DEFAULTIMAGE_URL = "~/Image/default.bmp";
public void ProcessRequest (HttpContext context) 
{
    System.Drawing.Image Cover;
    //判斷請求的物理路徑中是否存在被請求的圖片文件
    if (File.Exists(context.Request.PhysicalPath))
    {
        //加載圖片文件
        Cover = Image.FromFile(context.Request.PhysicalPath);
        //加載水印圖片
        Image watermark = Image.FromFile(context.Request.MapPath(WATERMARK_URL));
        //實例化畫布
        Graphics g = Graphics.FromImage(Cover);
        //在image上繪製水印
        //Rectangle部分設置畫的大小,圖片根據它來縮放。後面的指定要用來畫上去的圖片,畫那一部分。(起始點大小,表明載取的圖片放到前面的指定大小裏面去)
        g.DrawImage(watermark, new Rectangle(Cover.Width - watermark.Width, Cover.Height - watermark.Height, watermark.Width, watermark.Height), 0, 0, watermark.Width, watermark.Height, GraphicsUnit.Pixel);
        //釋放畫布
        g.Dispose();
        //釋放水印圖片
         watermark.Dispose();
    }
    else
    {
        //若是被請求的圖片不存在時,加載默認圖片
        Cover = Image.FromFile(context.Request.MapPath(DEFAULTIMAGE_URL));
    }
    //設置輸出格式
    cotext.Response.ContentType = "image/jpeg";
    //將圖片存入輸出流
    Cover.Save(context.Response.OutputStream, 
System.Drawing.Imaging.ImageFormat.Jpeg);
    Cover.Dispose();
    context.Response.End();
}

    public bool IsReusable 
    {
        get {
            return false;
        }
    }
}

3、全局配置HttpHandler

要讓系統自動捕獲對圖片訪問的請求,須要在項目裏Web.config配置文件中添加httpHandlers配置節進行配置。代碼以下所示:

<system.web>
    ......
<httpHandlers>
         <add path="*.jpg" verb="*" validate="false" type="CoverHandler"/>
     </httpHandlers>
</system.web>

各項屬性表明含義以下:
path:必選屬性。指定路徑屬性能夠包含單個URL路徑或簡單的通配符字符串(如 *.aspx)。「*」爲通配符。
verb:必選的屬性。指定謂詞列表能夠是逗號分隔的Http謂詞列表(例如,「GET, PUT, POST」),也能夠是開始腳本映射。「*」爲通配符。
validate:可選屬性。若是爲false,則ASP.NET在實際匹配請求到達以前將不嘗試加載該類。這有可能延遲錯誤,但減小了啓動時間。
type:必選屬性。指定逗號分隔的類/程序集組合。ASP.NET首先在應用程序的專用\bin目錄中搜索程序集DLL,而後在系統程序集緩存中搜索程序集DLL。

這樣,當客戶端發送訪問jpg文件時,系統會自動截獲請求轉交給CoverHandler類處理。

但要注意的是,使用這種配置方式,在開發服務器上運行時沒有問題。但若是在IIS上運行(經典模式),將會沒有任何效果。這是由於開發服務器僅提供最簡單的Web服務器功能,它不對請求的內容作任何處理,而是直接將全部的請求轉交給ASP.NET處理。IIS是一個比較完善且功能強大的Web服務器。全部提交到IIS的請求,會在IIS上作一些分類處理,所依據的原則就是後綴名。默認狀況下,.html、.jpg等靜態格式的文件IIS會本身處理,直接將結果返回到客戶端。只有當後綴名符合相關條件的(如.aspx),纔將請求轉交給ASP.NET進行處理。

也就是說IIS根本沒有把請求提交給ASP.NET處理。所以咱們須要對IIS做配置。

打開IIS信息服務管理器,在IIS欄目下打開「處理程序映射」功能。

能夠看到不一樣後綴名的請求對應不一樣的處理程序。點擊界面右側「添加腳本映射」。

填寫相關內容後點擊「肯定」,新的映射添加成功,並出如今映射列表中

這樣當客戶端請求的內容帶有.jpg後綴名時,IIS即會把該請求轉交給ASP.NET處理。達到返回的是帶水印的圖片。

4、局部調用HttpHandler

若是不須要對所有圖片資源都添加數字水印,能夠不採用上一節中說到的全局配置HttpHandler處理類的方式,而是使用通常處理程序對圖片資源進行處理。

選中項目點擊右鍵,選擇「添加新項」,選擇「通常處理程序」,這裏咱們把通常處理程序命名爲「PictureWaterMark」。系統建立的PictureWaterMark.ashx通常處理程序代碼;代碼跟咱們上面的基本一致,多了一個接受圖片路徑參數的,

 string covername = context.Request.QueryString["covername"];調用的時候,能夠:

<asp:Image ID="Image1" runat="server" ImageUrl='<%# Eval("covername", "~/ PictureWaterMark.ashx?covername={0}") %>' />

全局配置與局部調用HttpHandler兩種方式各有優缺點,全局的配置是全面覆蓋的,不管在哪一個頁面訪問圖片都被加上水印,而局部調用通常處理程序的方式只會在指定的訪問時才加水印,它的使用比較靈活,但不便於維護。在開發過程當中能夠根據實際需求狀況考慮使用那一種方式。

5、HttpHandler訪問Session

在HttpHandler處理程序中,雖然ProcessRequest中有HttpContext對象,但在這裏context對象卻不能訪問Session對象,使開發變得很是不方便。爲了使HttpHandler處理程序可以訪問Session對象,在類中除了繼承IHttpHandler接口外,還須要引用System.Web.SessionState命名空間,並實現接口IReadOnlySessionStateIRequiresSessionState

若是要在HttpHandler中讀取Session的內容,就要實現IReadOnlySessionState 這個接口。

若是要在HttpHandler中讀寫Session的內容,就要實現IRequiresSessionState這個接口。

這兩個接口沒有須要實現的方法,可直接使用。兩個接口的聲明以下所示:

IRequiresSessionState接口:
namespace System.Web.SessionState
{
    // 摘要:
    // 指定目標 HTTP 處理程序須要對會話狀態值具備讀寫訪問權。這是一個標記接口,沒有任何方法。
    public interface IRequiresSessionState
    {
    }
}
IReadOnlySessionState接口:
namespace System.Web.SessionState
{
    // 摘要:
    // 指定目標 HTTP 處理程序只須要具備對會話狀態值的讀訪問權限。這是一個標記接口,沒有任何方法。
    public interface IReadOnlySessionState : IRequiresSessionState
    {
    }
}
這裏能看到,其實IReadOnlySessionState接口是繼承了IRequiresSessionState接口。
相關文章
相關標籤/搜索