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命名空間,並實現接口IReadOnlySessionState或IRequiresSessionState。
若是要在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接口。