首页 > 开发 > 综合 > 正文

Community Server专题四:HttpHandler

2024-07-21 02:29:28
字体:
来源:转载
供稿:网友

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表