惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
Microsoft Security Blog
Microsoft Security Blog
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
罗磊的独立博客
腾讯CDC
云风的 BLOG
云风的 BLOG
月光博客
月光博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
宝玉的分享
宝玉的分享
U
Unit 42
I
InfoQ
D
DataBreaches.Net
Blog — PlanetScale
Blog — PlanetScale
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
V2EX
美团技术团队
IT之家
IT之家
Stack Overflow Blog
Stack Overflow Blog
F
Fortinet All Blogs
GbyAI
GbyAI
S
SegmentFault 最新的问题

博客园 - 零点时刻

一千万条数据数据搜索问题! 嵌套DataGrid,中如何添加删除事件?(望能暂时放一下,谢谢了!) 嵌套DataGrid,中如何添加删除事件? 计算机类资源网:http://www.3human.com/ 互动形式 用户可以上传资料 今天心情有点郁闷! 动态加载用户控件的组件!(二) (转) 动态加载用户控件的组件!(四) Asp.Net Forums研究文章集合(收藏) 【MasterPages实用技巧】为模板增加前端控制①——自动生成页面标题 【MasterPages实用技巧】使用MasterPages实现Web窗体模板 CS研究笔记-缓存 (转) Community Server专题八:MemberRole之Membership (转) 主板故障的分析和诊断 c# arraylist functions http://www.metabuilders.com/ 的MasterPages 控件可以多重嵌套 动态加载用户控件的组件!(转) 自定义控件主题使用研究 MasterPages(转载) 我的野外拍摄
Community Server专题四:HttpHandler
零点时刻 · 2006-04-06 · via 博客园 - 零点时刻

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()
{
//
// TOD 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控制权限的,而且需要浪费一些系统资源。