httpHandlers与Http处理程序

ASP.NET HTTP 处理程序是响应对 ASP.NET Web 应用程序的请求而运行的过程(通常称为"终结点")。最常用的处理程序是处理 .aspx 文件的 ASP.NET 页处理程序。用户请求 .aspx 文件时,页通过页处理程序来处理请求。

ASP.NET 页处理程序仅仅是一种类型的处理程序。ASP.NET 还包括其他几种内置的处理程序,例如用于 .asmx 文件的 Web 服务处理程序。

如果您需要进行特殊处理(可以在应用程序中使用文件扩展名进行标识),可以创建自定义 HTTP 处理程序。例如,下面的方案就很好地利用了自定义 HTTP 处理程序:

  • RSS 源   若要为站点创建 RSS 源,可以创建一个可发出 RSS 格式 XML 的处理程序。然后将您应用程序中的 .rss 扩展名(举例)绑定到此自定义处理程序。当用户向站点发送以 .rss 结尾的请求时,ASP.NET 将调用您的处理程序来处理请求。
  • 图像服务器   如果希望 Web 应用程序能够提供不同大小的图像,可以编写一个自定义处理程序来调整图像大小,然后将调整后的图像作为处理程序的响应返回给用户。

HTTP 处理程序可以访问应用程序上下文,包括请求用户的标识(如果已知)、应用程序状态和会话信息等。当请求 HTTP 处理程序时,ASP.NET 将调用相应处理程序上的 ProcessRequest 方法。处理程序的 ProcessRequest 方法创建一个响应,此响应随后发送回请求浏览器。就像任何页请求那样,响应将途经订阅了处理程序运行后所发生事件的所有 HTTP 模块。有关处理 Web 服务器请求的更多信息,请参见 ASP.NET 应用程序生命周期概述

HTTP 处理程序可以是同步的也可以是异步的。同步处理程序在完成对为其调用该处理程序的 HTTP 请求的处理后才会返回。异步处理程序运行进程的行为与向用户发送响应无关。当您需要启动一个可能耗费很长时间的应用程序进程,而用户又无需等候进程完成以便从服务器获取响应时,异步处理程序非常有用。

ASP.NET 中的内置 HTTP 处理程序

ASP.NET 根据文件扩展名将 HTTP 请求映射到 HTTP 处理程序。每个 HTTP 处理程序都能够处理应用程序中的单个 HTTP URL 或 URL 扩展名组。ASP.NET 包括几种内置的 HTTP 处理程序,如下表所列。

处理程序

说明

ASP.NET 页处理程序 (*.aspx)

用于所有 ASP.NET 页的默认 HTTP 处理程序。

Web 服务处理程序 (*.asmx)

用于使用 ASP.NET 创建的 Web 服务页的默认 HTTP 处理程序。

ASP.NET 用户控件处理程序 (*.ascx)

用于所有 ASP.NET 用户控件页的默认 HTTP 处理程序。

跟踪处理程序 (trace.axd)

显示当前页跟踪信息的处理程序。有关详细信息,请参见如何:使用跟踪查看器查看 ASP.NET 跟踪信息

如上面配置所示,.NET Framework配置中添加的Handler,实际后面还跟了一堆,不过都是同一种HttpFrobiddenHandler

创建自定义 HTTP 处理程序

若要创建一个自定义 HTTP 处理程序,可以创建一个可实现 IHttpHandler 接口的类以创建同步处理程序,或者创建一个可实现 IHttpAsyncHandler的类以创建异步处理程序。两种处理程序接口都要求您实现 IsReusable 属性和 ProcessRequest 方法。IsReusable 属性指定 IHttpHandlerFactory对象(实际调用适当处理程序的对象)是否可以将您的处理程序放置在池中,并且重新使用它们以提高性能,或是否在每次需要处理程序时都必须创建新实例。ProcessRequest 方法负责实际处理单个 HTTP 请求。

创建文件扩展名

创建一个类文件作为您的 HTTP 处理程序时,可以让您的处理程序响应尚未在 IIS 和 ASP.NET 中映射的任何文件扩展名。例如,如果您在创建用于生成 RSS 源的 HTTP 处理程序,则可以将处理程序映射到扩展名 .rss。为了让 ASP.NET 知道哪个处理程序将用于您的自定义文件扩展名,必须在 IIS 中将处理程序类文件的扩展名映射到 ASP.NET,并且在您的应用程序中将该扩展名映射到您的自定义处理程序。

默认情况下,ASP.NET 为自定义 HTTP 处理程序映射文件扩展名 .ashx 的方式与将扩展名 .aspx 映射到 ASP.NET 页处理程序的方式相同。因此,如果您创建具有文件扩展名 .ashx 的 HTTP 处理程序类,该处理程序将自动注册到 IIS 和 ASP.NET。

如果想要为您的处理程序创建自定义文件扩展名,则必须显式将该扩展名注册到 IIS 和 ASP.NET。不使用文件扩展名 .ashx 的好处是您的处理程序随后可以重新用于其他扩展名映射。例如,在某个应用程序中,您的自定义处理程序可能响应以 .rss 结尾的请求,而在另一个应用程序中,您的自定义处理程序可能响应以 .feed 结尾的请求。再举一例,您的处理程序可能映射到同一应用程序中的两个文件扩展名,但可能基于扩展名创建两个不同的响应。

下面通过一个例子来演示httpHandler的建立,注册以及效果

在App_Code中添加类ApkHandler实现接口IHttpHandler

 

namespace FastDoge.Study
{
    public class ApkHandler : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            HttpRequest Request = context.Request;
            HttpResponse Response = context.Response;
            // This handler is called whenever a file ending 
            // in .sample is requested. A file with that extension
            // does not need to exist.
            Response.Write("<html>");
            Response.Write("<body>");
            Response.Write("<h1>Hello from a synchronous custom HTTP handler.</h1>");
            Response.Write("</body>");
            Response.Write("</html>");
        }
        public bool IsReusable
        {
            // To enable pooling, return true here.
            // This keeps the handler in memory.
            get { return false; }
        }
    }
}

 

 

 

接着到Web.config中注册Hanler,这里对于两个不同版本的IIS也会有出入

在 IIS 6.0 和 IIS 7.0 经典模式下运行的Web.config添加以下配置

    <httpHandlers>
      <add verb="*" path="*.apk" 
        type="FastDoge.Study.ApkHandler" />
    </httpHandlers>

 

verb指定谓词列表可以是逗号分隔的 HTTP 谓词列表(例如,"GET, PUT, POST"),也可以是开始脚本映射(如星号 [*] 通配符)。

path:指定路径属性可以包含单个 URL 路径或简单的通配符字符串(如 *.aspx)。

type:指定逗号分隔的类/程序集组合。ASP.NET 首先在应用程序的专用 \bin 目录中搜索程序集 DLL,然后在系统程序集缓存中搜索程序集 DLL。

IIS7集成模式配置如下

  <system.webServer>
    <handlers>
      <add name="ApkHandler" verb="*"
        path="*.apk"
        type="FastDoge.Study.ApkHandler"
        resourceType="Unspecified" />
    </handlers>
  </system.webServer>

 

在运行后在浏览器中输入一个以apk为后缀的url

在MSDN中提到的可以在IIS中通过图形界面注册,这里就不尝试了,可参考https://msdn.microsoft.com/zh-cn/library/bb515343(v=vs.100).aspx。当然如果不在配置文件中添加,要是在HttpModule中指定,要与HttpModule耦合在一起的话就如上篇所说调用HttpContext.RemapHandler方法,如在上篇提到的MyModule类中作以下改动

        private void Application_BeginRequest(Object source,
        EventArgs e)
        {
            HttpApplication application = (HttpApplication)source;
            HttpContext context = application.Context;
            context.Response.Write("<h1><font color=red>" +
                "HelloWorldModule: Beginning of Request" +
                "</font></h1><hr>");

            string filePath = context.Request.FilePath;
            string fileExtension =
                VirtualPathUtility.GetExtension(filePath);
            if (fileExtension.Equals(".apk", StringComparison.InvariantCultureIgnoreCase) &&
                 context.Request.HttpMethod.Equals("GET"))
            {
                context.RemapHandler(new ApkHandler());
            }
        }

 

去掉Web.config的配置,访问以上URL有同样的效果。

   

异步 HTTP 处理程序

利用异步 HTTP 处理程序可以启动一个外部进程(例如对远程服务器的方法调用),然后继续处理程序的处理工作,而无需等待外部进程结束。在异步 HTTP 处理程序的处理期间,ASP.NET 将通常用于外部进程的线程放回线程池中,直到处理程序收到来自外部进程的回调。这样可以避免阻止线程,并大幅改善了性能,因为一次所能执行的线程数量是有限的。如果许多用户都在请求依赖于外部进程的同步 HTTP 处理程序,那么操作系统可能很快就会用完所有线程,因为大量线程被阻止,正在等待外部进程。

创建异步处理程序时,除了实现 IHttpAsyncHandler 接口,还必须实现 BeginProcessRequest 以启动异步调用来处理单个 HTTP 请求。还必须实现 EndProcessRequest 方法,以便在进程结束时运行清理代码。

下面则定义了一个AsyncApkHandler的异步处理程序,在BeginProcessRequest时调用一个AsynchOperation,该类实现IAsyncResult接口,需要异步操作的代码在方法StartAsyncWork()中调用

 

namespace FastDoge.Study
{
    public class AsyncApkHandler : IHttpAsyncHandler
    {
        public bool IsReusable { get { return false; } }

  
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
        {
            context.Response.Write("<p>Begin IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + " " + DateTime.Now + "  " + Thread.CurrentThread.ManagedThreadId + "</p>\r\n");
            AsynchOperation asynch = new AsynchOperation(cb, context, extraData);
            asynch.StartAsyncWork();
            return asynch;
        }

        public void EndProcessRequest(IAsyncResult result)
        {
            if (result is AsynchOperation)
            {
                (result as AsynchOperation).Context.Response.Write("<p>End IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + "  "+DateTime.Now+"  " + Thread.CurrentThread.ManagedThreadId + "</p>\r\n");
            }
        }

        public void ProcessRequest(HttpContext context)
        {
            throw new InvalidOperationException();
        }
    }

    class AsynchOperation : IAsyncResult
    {
        private bool _completed;
        private Object _state;
        private AsyncCallback _callback;
        private HttpContext _context;

        bool IAsyncResult.IsCompleted { get { return _completed; } }
        WaitHandle IAsyncResult.AsyncWaitHandle { get { return null; } }
        Object IAsyncResult.AsyncState { get { return _state; } }
        bool IAsyncResult.CompletedSynchronously { get { return false; } }

        public HttpContext Context
        {
            get
            {
                return _context;
            }
        }

        public AsynchOperation(AsyncCallback callback, HttpContext context, Object state)
        {
            _callback = callback;
            _context = context;
            _state = state;
            _completed = false;
        }

        public void StartAsyncWork()
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncTask), null);
        }

        private void StartAsyncTask(Object workItemState)
        {
            Thread.Sleep(3000);
            _context.Response.Write("<p>Completion IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + "  " + DateTime.Now + " " + Thread.CurrentThread.ManagedThreadId + "</p>\r\n");

            _context.Response.Write("Hello World from Async Handler!");
            _completed = true;
            _callback(this);
        }
    }
}

 

 

配置方式如之前的方式。效果如下

   

自定义 IHttpHandlerFactory 类

IHttpHandlerFactory 类接收请求并负责向相应的 HTTP 处理程序转发请求。您可以通过创建一个实现了 IHttpHandlerFactory 接口的类来创建自定义 HTTP 处理程序工厂。创建自定义处理程序工厂可以更好地控制对 HTTP 请求的处理,因为这样可以基于运行时条件创建不同的处理程序。例如,使用自定义 HTTP 处理程序工厂,可以在 HTTP 请求方法为 PUT 时为某个文件类型实例化一个 HTTP 处理程序,而在该方法为 GET 时实例化另一个 HTTP 处理程序。又例如,通过使用 HTTP 处理程序工厂,可以创建有限数量的 HTTP 处理程序对象,来访问诸如数据库连接等昂贵或有限的资源。然后,可以在以后的请求中重用这些处理程序对象。

IHttpHandlerFactory 有两个方法

IHttpHandler GetHandler返回实现 System.Web.IHttpHandler 接口的类的实例

void ReleaseHandler使工厂可以重用现有的处理程序实例。

下面则定义个ApkHanlderFactory,同时在ApkHandler 输出的内容上有稍作修改(输出当前HttpHandler的HashCode)

 

namespace FastDoge.Study
{
    public class ApkHanlderFactory : IHttpHandlerFactory
    {
        private ApkHandler _cacheHandler;

        private ApkHandler CacheHandler
        {
            get
            {
                if (_cacheHandler == null)
                {
                    _cacheHandler = new ApkHandler();
                }
                return _cacheHandler;
            }
        }

        public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
        {
            if (context.Request.QueryString.AllKeys.Contains("IsCache") &&
                context.Request["IsCache"].ToLower().Equals("true", StringComparison.InvariantCultureIgnoreCase))
            {
                return CacheHandler;
            }
            return new ApkHandler();
        }

        public void ReleaseHandler(IHttpHandler handler)
        {
            
        }
    }
}

 

 

配置文件方面与注册IHttpHandler基本一致,只是type特性中填写的是实现IHttpHandlerFactory接口的类名,但是在Module中通过编码的形式指定的方式暂时没找到,估计需要看源码了。

请求URL如下URL时,响应的html内容一直不变

如果去除IsCache参数时,内容则每次都在变化。

   

   

参考内容

HTTP 处理程序介绍

来自 <https://msdn.microsoft.com/zh-cn/library/ms227675(v=vs.100).aspx>

HTTP 处理程序和 HTTP 模块概述

来自 <https://msdn.microsoft.com/zh-cn/library/bb398986(v=vs.100).aspx>

posted @ 2016-09-25 10:43  猴健居士  阅读(2434)  评论(1编辑  收藏  举报