Community Server專題四:HttpHandlera

Community Server專題四:HttpHandler

HttpHandler實現了ISAPI Extention的功能,他處理請求(Request)的信息和發送響應(Response)HttpHandler功能的實現通過實現IHttpHandler接口來達到。

看圖先:

ASP.NET 管道處理的末端是HTTP Hander,其實每個Asp.netPage都實現了IHttpHander,在VS.net中的對象察看器中你可以證實這一點

具體的類是這樣定義的:public class Page : TemplateControl, IhttpHandler

接口IHttpHandler的定義如下:

 

 

 

interface IHttpHandler

{

void ProcessRequest(HttpContext ctx);

bool IsReuseable get; }

}

接口中

CS中有很多繼承IHttpHandler接口的類,我取出有代表性而又容易理解的一個做分析:找到CommunityServerComponents項目Components目錄下的Redirect.cs文件,內容如下:

 

這裏的Redirect功能是在web請求滿足HttpHandler配置文件中預設條件下自動攔截執行的,在web.config<httpHandlers>節點下可以看到

//------------------------------------------------------------------------------
// <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; }
        }

    }

}

 

<add verb="GET" path="Utility/redirect.aspx" type="CommunityServer.Components.Redirect, CommunityServer.Components" />


對該類的配置

· verb可以是"GET""POST",表示對GETPOST的請求進行處理。"*"表示對所有請求進行處理,這裏是對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方法是對當前請求的上下文ContextUrl是否包含“u”參數,如果有並且參數值不爲null就調用Response.Redirect方法跳轉到“u”參數值所執行的頁面,如果沒有參數或者參數值爲空就跳轉到CS的首頁)

另外在CS中對RSSTrackback的處理都使用了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都做了什麼
 
.Text的早期版本中(很久沒有看.Text的代碼了)安裝時要配置IIS

[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, 24);
                  
this.GetDelegateInformation("Page_Load"ref vector1, 80x10);
                  
this.GetDelegateInformation("Page_DataBind"ref vector1, 0x200x40);
                  
this.GetDelegateInformation("Page_PreRender"ref vector1, 0x800x100);
                  
this.GetDelegateInformation("Page_Unload"ref vector1, 0x2000x400);
                  
this.GetDelegateInformation("Page_Error"ref vector1, 0x8000x1000);
                  
this.GetDelegateInformation("Page_AbortTransaction"ref vector1, 0x20000x4000);
                  
this.GetDelegateInformation("OnTransactionAbort"ref vector1, 0x80000x10000);
                  
this.GetDelegateInformation("Page_CommitTransaction"ref vector1, 0x200000x40000);
                  
this.GetDelegateInformation("OnTransactionCommit"ref vector1, 0x800000x100000);
                  
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,頁面處理是從這裏開始。

 

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

這時,IIS會把對*.html文件的請求也交由ASP.NET機制去處理,繼承IHttpHandler就可以攔截它(.Text中實際繼承的是IHttpHandlerFactory)。有了這些知識就不難理解爲什麼你在.Text系統下察看blog時請求的是html文件(其實請求的html文件根本就不存在),返回的信息確是動態頁面的內容,這與大型CMS系統不同,並不是爲了節約系統資源預先生成htmlDotText之所以這樣做牽涉到PermalinkSearch Engine Friendly,有這方面興趣的朋友可以在google找到很多相關資源。


    雖然
CS中的blog.Text有密不可分的關係,但是CS中的blog已經沒有采取早期.TextUrl擴展名爲.html的訪問機制,而是直接採用.aspx擴展名,也許更多考慮的是CS的部署問題,畢竟不是所有的CS使用者都會有可以自己配置IIS擴展名映射的權限,大多數虛擬主機也是不提供這樣功能的。

HttpHandler還可以用來處理圖片與下載的盜鏈問題,先在IIS中添加一些常用圖片擴展名的映射到IIS中用Asp.net來處理對它的請求,這樣就可以通過繼承IHttpHandler的類和適當的配置來處理用戶的請求,大致說一下過程:

在實現IHttpHandler接口的類中,ProcessRequest方法先用判斷上次請求的URL(爲什麼是判斷上次請求的URL,請看我上一篇專題中對IIS運行過程的講解),如果這個URL是在你限定內那麼就調用Response.WriteFile方法輸出文件,如果不是,你可以自己採取一些措施,比如輸出一個帶有警告字樣的圖片等等。當然,使用HttpHandler處理圖片與下載盜鏈問題是需要IIS控制權限的,而且需要浪費一些系統資源。

ProcessRequest是添加自己的代碼進行相應處理的地方。IsReuseable屬性指明該HttpHandler的實現類是否需要緩存。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章