Extended IHttpHandler

  As previously mentioned request into the IIS, IIS forwarded to the ISAPI will decide to forward the request to be processed corresponding processing program according to the file extension, of course, a large part of the processing is handed over to AspNet_ISAPI. However, AspNet_ISAPI impossible for all of the files use the same approach, so now we have to analyze is how AspNet_ISAPI further requests to be processed.

  Open the IIS site, find processing program map, you can see different suffix file handler also correspondingly different. Thus AspNet_ISAPI requests assigned to different processing Handler.

Then the handler is how to register it? We open the C: \ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ web.config file in the Config directory, find httphandlers node, depending on the suffix, .Net framework has been configured with some default Handler handler for us.

    <httpHandlers>
            <add path="eurl.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True"/>
            <add path="trace.axd" verb="*" type="System.Web.Handlers.TraceHandler" validate="True"/>
            <add path="WebResource.axd" verb="GET" type="System.Web.Handlers.AssemblyResourceLoader" validate="True"/>
            <add verb="*" path="*_AppService.axd" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>
            <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>
            <add path="*.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True"/>
            <add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True"/>
            <add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True"/>
            <add path="*.asmx" verb="*" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>
            <add path="*.rem" verb="*" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="False"/>
            <add path="*.soap" verb="*" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="False"/>
            <add path="*.asax" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.ascx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.master" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.skin" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.browser" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.sitemap" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.dll.config" verb="GET,HEAD" type="System.Web.StaticFileHandler" validate="True"/>
            <add path="*.exe.config" verb="GET,HEAD" type="System.Web.StaticFileHandler" validate="True"/>
            <add path="*.config" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.cs" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.csproj" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.vb" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.vbproj" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.webinfo" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.licx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.resx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.resources" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.mdb" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.vjsproj" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.java" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.jsl" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.ldb" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.ad" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.dd" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.ldd" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.sd" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.cd" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.adprototype" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.lddprototype" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.sdm" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.sdmDocument" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.mdf" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.ldf" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.exclude" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.refresh" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>
            <add path="*.rules" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.xoml" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>
            <add path="*.xamlx" verb="*" type="System.Xaml.Hosting.XamlHttpHandlerFactory, System.Xaml.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>
            <add path="*.aspq" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.cshtm" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.cshtml" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.vbhtm" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*.vbhtml" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            <add path="*" verb="GET,HEAD,POST" type="System.Web.DefaultHttpHandler" validate="True"/>
            <add path="*" verb="*" type="System.Web.HttpMethodNotAllowedHandler" validate="True"/>
        </httpHandlers>

  那么这些Handler 的执行时机是在什么时候呢?前面我们提到请求进入asp.net管道后创建了HttpApplication,接着执行一堆事件,每个事件完成自己的工作。因为在上面我们从IIS的处理程序映射图可以看出,当IIS7以上并且是集成模式的时候请求才交给了Handler进行处理,经典模式的处理程序是IsapiModule。所以我们可以理解为在管道处理事件中,有一些事件是只支持IIS7以上的。其中就有MapRequestHandler 事件,当请求执行到该事件时,MapRequesthandler事件负责制定具体的handler处理请求,例如处理.ashx一般处理程序,.aspx页面,处理结束后继续往下执行其他事件。

  既然MapRequestHandler只支持IIS7集成模式,那么IIS6呢,其实IIS6 会根据URL路径或扩展名和匹配规则(配置文件设置或Routing配置)进行查找,创建并赋值给HttpContext.Handler属性,然后在PreRequestHandlerExecute事件后调用HttpContext.Handler属性的ProcessRequest或BeginProcesssRequest方法。

  理解了HttpHandler的原理后,如果我们要自定义自己的Handler处理一些特殊的请求时,我们该怎么做呢?继续往下看。

  要自定义自己的Handler处理程序,.Net框架为我们提供了IHttpHandler接口,我们需要定义一个类并实现IHttpHandler接口。

    //
    // 摘要:
    //     Defines the contract that ASP.NET implements to synchronously process HTTP Web
    //     requests using custom HTTP handlers.
    public interface IHttpHandler
    {
        //
        // 摘要:
        //     Gets a value indicating whether another request can use the System.Web.IHttpHandler
        //     instance.
        //
        // 返回结果:
        //     true if the System.Web.IHttpHandler instance is reusable; otherwise, false.
        bool IsReusable { get; }

        //
        // 摘要:
        //     Enables processing of HTTP Web requests by a custom HttpHandler that implements
        //     the System.Web.IHttpHandler interface.
        //
        // 参数:
        //   context:
        //     An System.Web.HttpContext object that provides references to the intrinsic server
        //     objects (for example, Request, Response, Session, and Server) used to service
        //     HTTP requests.
        void ProcessRequest(HttpContext context);
    }

  接下来我们定义一个ImageHandler类,该类实现IHttpHandler接口。

namespace Jesen.Web.Core.HttpHandler
{
    /// <summary>
    /// 自定义图片处理程序,通过Request请求中的UrlReferrer来判断是否是自己的站点所请求的,以此来防盗链
    /// </summary>
    public class ImageHandler : IHttpHandler
    {
        #region IHttpHandler Members

        public bool IsReusable
        {
            get { return true; }
        }

        public void ProcessRequest(HttpContext context)
        {
            if (context.Request.UrlReferrer == null || context.Request.UrlReferrer.Host == null)
            {
                context.Response.ContentType = "image/JPEG";
                context.Response.WriteFile("/Content/Image/Forbidden.jpg");
            }
            else
            {
                if (context.Request.UrlReferrer.Host.Contains("localhost"))
                {
                    string FileName = context.Server.MapPath(context.Request.FilePath);
                    context.Response.ContentType = "image/JPEG";
                    context.Response.WriteFile(FileName);
                }
                else
                {
                    context.Response.ContentType = "image/JPEG";
                    context.Response.WriteFile("/Content/Image/Forbidden.jpg");
                }
            }
        }

        #endregion
    }
}

现在我们已经准备好了一个Handler处理程序,接下来要做的就是在配置文件里面配置它,verb为请求方式POST/GET/HEAD等,type为类名,程序集名。

<system.webServer>
    <handlers>
      <add name="gif" path="*.gif" verb="*" type="Jesen.Web.Core.HttpHandler.ImageHandler,Jesen.Web.Core" />
      <add name="png" path="*.png" verb="*" type="Jesen.Web.Core.HttpHandler.ImageHandler,Jesen.Web.Core" />
      <add name="jpg" path="*.jpg" verb="*" type="Jesen.Web.Core.HttpHandler.ImageHandler,Jesen.Web.Core" />
      <add name="jpeg" path="*.jpeg" verb="*" type="Jesen.Web.Core.HttpHandler.ImageHandler,Jesen.Web.Core" />

    </handlers>
  </system.webServer>

  接着我们运行它,如果是采用MVC的,需要在路由注册时忽略它,在RouteConfig中添加 routes.IgnoreRoute("Handler/{*pathInfo}"); 便可以通过/Handler/123.jpg来访问。

  .Net框架也提供了IHttpHandlerFactory接口,通过注册HandlerFactory,可以为不同的后缀指定不同的handler。

 

public class ImageHandlerFactory : IHttpHandlerFactory
    {
        public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
        {
            string path = context.Request.PhysicalPath;
            if (Path.GetExtension(path).Equals(".gif"))
            {
                return new GifHandler();
            }
            else if (Path.GetExtension(path) == ".png")
            {
                return new PngHandler();
            }
            else
            {
                return new ImageHandler();
            }
        }

        public void ReleaseHandler(IHttpHandler handler)
        {
        }
    }
<system.webServer>
    <handlers>
          <add name="imagefactory" path="*.gif,*.png,*.jpg,*.jpeg" verb="*" type="Jesen.Web.Core.HttpHandler.ImageHandlerFactory,Jesen.Web.Core" />

    </handlers>
  </system.webServer>

到此,httphandler的扩展就介绍到这里,下一篇来介绍MVC中的Handler。

Guess you like

Origin www.cnblogs.com/jesen1315/p/11002810.html