httphandler實現了isapi extention的功能,他處理請求(request)的信息和發送響應(response)。httphandler功能的實現通過實現ihttphandler接口來達到。
看圖先:

在asp.net 管道處理的末端是http hander,其實每個asp.net的page都實現了ihttphander,在vs.net中的對象察看器中你可以證實這一點

具體的類是這樣定義的:public class page : templatecontrol, ihttphandler。
接口ihttphandler的定義如下:
interface ihttphandler
{
void processrequest(httpcontext ctx);
bool isreuseable { get; }
}
接口中processrequest是添加自己的代碼進行相應處理的地方。isreuseable屬性指明該httphandler的實現類是否需要緩存。
在cs中有很多繼承ihttphandler接口的類,我取出有代表性而又容易理解的一個做分析:找到communityservercomponents項目components目錄下的redirect.cs文件,內容如下:
//------------------------------------------------------------------------------
// <copyright company="telligent systems">
// copyright (c) telligent systems corporation. all rights reserved.
// </copyright>
//------------------------------------------------------------------------------
using system;
using system.web;
namespace communityserver.components
{
/**//// <summary>
/// summary description for redirect.
/// </summary>
public class redirect : ihttphandler
{
public redirect()
{
//
// todo: add constructor logic here
//
}
public void processrequest(httpcontext context)
{
string url = context.request.querystring["u"];
if(!globals.isnullorempty(url))
{
context.response.redirect(url);
}
else
{
context.response.redirect(globals.getsiteurls().home);
}
context.response.end();
}
public bool isreusable
{
get { return false; }
}
}
}
這里的redirect功能是在web請求滿足httphandler配置文件中預設條件下自動攔截執行的,在web.config中<httphandlers>節點下可以看到
<add verb="get" path="utility/redirect.aspx" type="communityserver.components.redirect, communityserver.components" />
對該類的配置
· verb可以是"get"或"post",表示對get或post的請求進行處理。"*"表示對所有請求進行處理,這里是對get請求進行處理。
· path指明對相應的文件進行處理,"*.aspx"表示對發給所有aspx頁面的請求進行處理,這里單獨對redirect.aspx頁面進行處理。可以指明路徑,如"blogs"。表明只對blogs目錄下的redirect.aspx文件請求進行處理。
· type屬性中,逗號前的字符串指明httphandler的實現類的類名,后面的字符串指明dll文件的名稱。
實際處理是怎么樣的呢?其實redirect.aspx頁面在cs項目中并不存在,cs把對redirect.aspx的請求處理交給了communityserver.components.dll程序集中redirect類進行處理。處理的過程是執行
public void processrequest(httpcontext context)
方法(redirect類下的processrequest方法是對當前請求的上下文context中url是否包含“u”參數,如果有并且參數值不為null就調用response.redirect方法跳轉到“u”參數值所執行的頁面,如果沒有參數或者參數值為空就跳轉到cs的首頁)。
另外在cs中對rss和trackback的處理都使用了httphandler的處理方式。
前面提到,所有頁面的基類page都實現了httphandler接口,因此每個asp.net的頁面都可以看成是一個httphandler處理類,只是配置部分在machine.config中
<httphandlers>
<add verb="*" path="*.vjsproj" type="system.web.httpforbiddenhandler"/><add verb="*" path="*.java" type="system.web.httpforbiddenhandler"/><add verb="*" path="*.jsl" type="system.web.httpforbiddenhandler"/><add verb="*" path="trace.axd" type="system.web.handlers.tracehandler"/>
<add verb="*" path="*.aspx" type="system.web.ui.pagehandlerfactory"/>
<add verb="*" path="*.ashx" type="system.web.ui.simplehandlerfactory"/>
<add verb="*" path="*.asmx" type="system.web.services.protocols.webservicehandlerfactory, system.web.services, version=1.0.5000.0, culture=neutral, publickeytoken=b03f5f7f11d50a3a" validate="false"/>
<add verb="*" path="*.rem" type="system.runtime.remoting.channels.http.httpremotinghandlerfactory, system.runtime.remoting, version=1.0.5000.0, culture=neutral, publickeytoken=b77a5c561934e089" validate="false"/>
<add verb="*" path="*.soap" type="system.runtime.remoting.channels.http.httpremotinghandlerfactory, system.runtime.remoting, version=1.0.5000.0, culture=neutral, publickeytoken=b77a5c561934e089" validate="false"/>
<add verb="*" path="*.asax" type="system.web.httpforbiddenhandler"/>
<add verb="*" path="*.ascx" type="system.web.httpforbiddenhandler"/>
<add verb="get,head" path="*.dll.config" type="system.web.staticfilehandler"/>
<add verb="get,head" path="*.exe.config" type="system.web.staticfilehandler"/>
<add verb="*" path="*.config" type="system.web.httpforbiddenhandler"/>
<add verb="*" path="*.cs" type="system.web.httpforbiddenhandler"/>
<add verb="*" path="*.csproj" type="system.web.httpforbiddenhandler"/>
<add verb="*" path="*.vb" type="system.web.httpforbiddenhandler"/>
<add verb="*" path="*.vbproj" type="system.web.httpforbiddenhandler"/>
<add verb="*" path="*.webinfo" type="system.web.httpforbiddenhandler"/>
<add verb="*" path="*.asp" type="system.web.httpforbiddenhandler"/>
<add verb="*" path="*.licx" type="system.web.httpforbiddenhandler"/>
<add verb="*" path="*.resx" type="system.web.httpforbiddenhandler"/>
<add verb="*" path="*.resources" type="system.web.httpforbiddenhandler"/>
<add verb="get,head" path="*" type="system.web.staticfilehandler"/>
<add verb="*" path="*" type="system.web.httpmethodnotallowedhandler"/>
</httphandlers>
借助一個工具:reflector,看看page類下的httphandler處理方法processrequest都做了什么
[editorbrowsable(editorbrowsablestate.never)]
public void processrequest(httpcontext context)
{
this.setintrinsics(context);
this.processrequest();
}
private void setintrinsics(httpcontext context)
{
this._context = context;
this._request = context.request;
this._response = context.response;
this._application = context.application;
this._cache = context.cache;
if ((this._clienttarget != null) && (this._clienttarget.length > 0))
{
this._request.clienttarget = this._clienttarget;
}
base.hookupautomatichandlers();
}
private void processrequest()
{
thread thread1 = thread.currentthread;
cultureinfo info1 = thread1.currentculture;
cultureinfo info2 = thread1.currentuiculture;
this.frameworkinitialize();
try
{
try
{
if (this.istransacted)
{
this.processrequesttransacted();
}
else
{
this.processrequestmain();
}
this.processrequestendtrace();
}
finally
{
this.processrequestcleanup();
internalsecuritypermissions.controlthread.assert();
thread1.currentculture = info1;
thread1.currentuiculture = info2;
}
}
catch
{
throw;
}
}
在page類的processrequest方法先是把上下文context內容賦值到當前page中的一些屬性里,然后調用system.web.ui.templatecontrol中的hookupautomatichandlers()
internal void hookupautomatichandlers()
{
if (this.supportautoevents)
{
simplebitvector32 vector1 = new simplebitvector32(this.autohandlers);
internalsecuritypermissions.reflection.assert();
if (!vector1[1])
{
vector1[1] = true;
this.getdelegateinformation("page_init", ref vector1, 2, 4);
this.getdelegateinformation("page_load", ref vector1, 8, 0x10);
this.getdelegateinformation("page_databind", ref vector1, 0x20, 0x40);
this.getdelegateinformation("page_prerender", ref vector1, 0x80, 0x100);
this.getdelegateinformation("page_unload", ref vector1, 0x200, 0x400);
this.getdelegateinformation("page_error", ref vector1, 0x800, 0x1000);
this.getdelegateinformation("page_aborttransaction", ref vector1, 0x2000, 0x4000);
this.getdelegateinformation("ontransactionabort", ref vector1, 0x8000, 0x10000);
this.getdelegateinformation("page_committransaction", ref vector1, 0x20000, 0x40000);
this.getdelegateinformation("ontransactioncommit", ref vector1, 0x80000, 0x100000);
this.autohandlers = vector1.data;
}
if (vector1[2])
{
base.init += this.getdelegatefrommethodname("page_init", vector1[4]);
}
if (vector1[8])
{
base.load += this.getdelegatefrommethodname("page_load", vector1[0x10]);
}
if (vector1[0x20])
{
base.databinding += this.getdelegatefrommethodname("page_databind", vector1[0x40]);
}
if (vector1[0x80])
{
base.prerender += this.getdelegatefrommethodname("page_prerender", vector1[0x100]);
}
if (vector1[0x200])
{
base.unload += this.getdelegatefrommethodname("page_unload", vector1[0x400]);
}
if (vector1[0x800])
{
this.error += this.getdelegatefrommethodname("page_error", vector1[0x1000]);
}
if (vector1[0x2000])
{
this.aborttransaction += this.getdelegatefrommethodname("page_aborttransaction", vector1[0x4000]);
}
else if (vector1[0x8000])
{
this.aborttransaction += this.getdelegatefrommethodname("ontransactionabort", vector1[0x10000]);
}
if (vector1[0x20000])
{
this.committransaction += this.getdelegatefrommethodname("page_committransaction", vector1[0x40000]);
}
else if (vector1[0x80000])
{
this.committransaction += this.getdelegatefrommethodname("ontransactioncommit", vector1[0x100000]);
}
}
}
方法連接一些handlers,通過委托加載相關的事件進行頁面的初始化工作。
我不再往下分析,整個page頁面很龐大,有興趣的朋友自己慢慢研究,說這些只是要明白一點,任何一個page頁面都是httphandler,頁面處理是從這里開始。
在.text的早期版本中(很久沒有看.text的代碼了)安裝時要配置iis

在asp.net管道處理的級別上對一些擴展名稱做映射,如*.html(其實.text是做了*.*到asp.net映射,夠狠!),該擴展名的文件原本直接由iis提交給請求者而不會經過asp.net處理機制處理,因此asp.net管道中的httphandler是不可能攔截到的,但是只要做如下操作

這時,iis會把對*.html文件的請求也交由asp.net機制去處理,繼承ihttphandler就可以攔截它(.text中實際繼承的是ihttphandlerfactory)。有了這些知識就不難理解為什么你在.text系統下察看blog時請求的是html文件(其實請求的html文件根本就不存在),返回的信息確是動態頁面的內容,這與大型cms系統不同,并不是為了節約系統資源預先生成html。dottext之所以這樣做牽涉到permalink和search engine friendly,有這方面興趣的朋友可以在google找到很多相關資源。
雖然cs中的blog與.text有密不可分的關系,但是cs中的blog已經沒有采取早期.text的url擴展名為.html的訪問機制,而是直接采用.aspx擴展名,也許更多考慮的是cs的部署問題,畢竟不是所有的cs使用者都會有可以自己配置iis擴展名映射的權限,大多數虛擬主機也是不提供這樣功能的。
httphandler還可以用來處理圖片與下載的盜鏈問題,先在iis中添加一些常用圖片擴展名的映射到iis中用asp.net來處理對它的請求,這樣就可以通過繼承ihttphandler的類和適當的配置來處理用戶的請求,大致說一下過程:
在實現ihttphandler接口的類中,processrequest方法先用
判斷上次請求的url(為什么是判斷上次請求的url,請看我上一篇專題中對iis運行過程的講解),如果這個url是在你限定內那么就調用response.writefile方法輸出文件,如果不是,你可以自己采取一些措施,比如輸出一個帶有警告字樣的圖片等等。當然,使用httphandler處理圖片與下載盜鏈問題是需要iis控制權限的,而且需要浪費一些系統資源。
商業源碼熱門下載www.html.org.cn
新聞熱點
疑難解答