扩展IHttpHandler
作者:互联网
前面提到当请求进入到IIS,IIS转发给ISAPI后会根据文件的后缀名来决定将请求转发给对应的处理程序进行处理,当然一大部分的处理都是交给了AspNet_ISAPI 了。但是,AspNet_ISAPI 不可能对所有的文件都采用同一种处理方式,所以现在我们就来分析一下AspNet_ISAPI是怎么进一步对请求进行处理的。
打开IIS站点,找到处理处理程序映射,可以看到不同后缀的文件,处理程序也相应的不同。由此可见AspNet_ISAPI将请求分配给了不同的Handler进行处理。
那么这些handler是如何注册的呢?我们打开 C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config目录下的web.config文件,找到httphandlers节点,根据不同后缀,.Net框架已经为我们配置了一些默认的Handler处理程序。
<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。
标签:Web,IHttpHandler,扩展,Handler,处理程序,context,请求 来源: https://www.cnblogs.com/jesen1315/p/11002810.html