管道处理模型二(摘抄cainong2005博客)

一.Httphandler:

在《模型一》的demo中,新建一个webform文件,MyWebForm.aspx,内容和简单,就是一行文字。

  1.   <body>
  2.   <form id="form1" runat="server">
  3.   <div>
  4.   This is MyWebForm
  5.   </div>
  6.   </form>
  7.   </body>

 运行结果:

管道处理模型二(摘抄cainong2005博客)管道处理模型二(摘抄cainong2005博客)

再看MyWebForm.aspx.cs文件代码:

  1.   public partial class MyWebForm : System.Web.UI.Page
  2.   {
  3.   protected void Page_Load(object sender, EventArgs e)
  4.   {
  5.    
  6.   }
  7.   }

没有别的代码,只是实现了System.Web.UI.Page,Page又是什么呢?F12跟进去:

管道处理模型二(摘抄cainong2005博客)

所以,在Webform中,我们申明的东西,写的页面,实现的业务逻辑,其实就是一个HttpHandler,而它是在PreRequestHandlerExecute 和 PostRequestHandlerExecute 这两个Event之间执行的。

这里有一个很重要的事件,MapRequestHandler,负责制定具体的handler处理请求:

管道处理模型二(摘抄cainong2005博客)

它是在哪里配置的呢?

全局的webconfig中,(C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\web.config)

管道处理模型二(摘抄cainong2005博客)

我们先用反编译工具,看看System.Web.UI.PageHandlerFactory:

管道处理模型二(摘抄cainong2005博客)

这个核心方法 GetHandlerHelper干什么的呢?它就是传入的参数,创建一个Page。

管道处理模型二(摘抄cainong2005博客)

其实从名字就能看的出来,PageHandlerFactory,PageHandler的工厂,当然输出Page。

还有web.config文件不能访问,就是因为已经配置了HttpForbiddenHandler,禁止访问。

管道处理模型二(摘抄cainong2005博客)

强行访问web.config,就报错了

管道处理模型二(摘抄cainong2005博客)

为什么禁止访问?HttpForbiddenHandler里面做了什么?反编译工具中看:

管道处理模型二(摘抄cainong2005博客)

既然知道了怎么给不同后缀名的请求配置不同处理的HttpHandler,那我们能不能自定义呢?可以的。例如自定义一个图片验证码请求的HttpHandler。步骤如下:

1.webconfig下,在handlers节点配置一个处理verify后缀的HttpHandler。

管道处理模型二(摘抄cainong2005博客)

2.建立VerifyCode类,并继承IHttpHandler,这个 是必须的。

管道处理模型二(摘抄cainong2005博客)

3.在浏览器中访问 http://localhost:8090/handler/1.verify ,报错

管道处理模型二(摘抄cainong2005博客)

错误很明显,是不存在handler控制器,那么在路由里面将它忽略掉吧。

4.忽略路由:

管道处理模型二(摘抄cainong2005博客)

5.浏览器再次访问 http://localhost:8090/handler/1.verify ,显示了正确的验证码图片。

管道处理模型二(摘抄cainong2005博客)

 

问题来了,这样自定义HttpHandler有什么价值?举个例子,可以做防盗链。

比如网上有很多图片“本图片仅限百度用户内部交流”,这就是百度图片做了防盗链,怎么做到的呢?就是用到了自定义的HttpHandler。步骤如下:

1.在web.config文件的  节点,针对图片类型,注册新的HttpHandler。

管道处理模型二(摘抄cainong2005博客)

2.在PipeController控制器中加一个Handler()方法。

  1.   public ViewResult Handler()
  2.   {
  3.   IHttpHandler handler = base.HttpContext.Handler;
  4.   ViewBag.HandlerName = handler.GetType().ToString();
  5.   ViewBag.Url = Request.Url.AbsoluteUri;
  6.   return View();
  7.   }

同时,Handler.cshtml中也添加代码。

  1.   @{
  2.   ViewBag.Title = "Handler";
  3.   }
  4.    
  5.   <h2>Handler</h2>
  6.   <p>@ViewBag.HandlerName</p>
  7.   <p>@ViewBag.Url</p>
  8.   <p>@Html.Image("/Content/Image/liuyan.jpg", "liuyan图片", "柳岩", new { id = "image" })</p>

运行一下,显示如图:

管道处理模型二(摘抄cainong2005博客)

3.F12打开浏览器的调试工具,看到了原图地址:

管道处理模型二(摘抄cainong2005博客)

4.既然已经找到了原图地址,在浏览器的新标签页打开,结果是这个样子:

管道处理模型二(摘抄cainong2005博客)

由此可见,直接输入图片地址是打不开的,也达到了防盗链的效果。下面讲一下是如何做到的

看看上面定义的ImageHandler类的ProcessRequest方法:

  1.   public void ProcessRequest(HttpContext context)
  2.   {
  3.   // 如果UrlReferrer为空,则显示一张默认的禁止盗链的图片
  4.   if (context.Request.UrlReferrer == null || context.Request.UrlReferrer.Host == null)
  5.   {
  6.   context.Response.ContentType = "image/JPEG";
  7.   context.Response.WriteFile("/Content/Image/Forbidden.jpg");
  8.   }
  9.   else
  10.   {
  11.   // 如果 UrlReferrer中不包含自己站点主机域名,则显示一张默认的禁止盗链的图片
  12.   if (context.Request.UrlReferrer.Host.Contains("localhost"))
  13.   {
  14.   // 获取文件服务器端物理路径
  15.   string FileName = context.Server.MapPath(context.Request.FilePath);
  16.   context.Response.ContentType = "image/JPEG";
  17.   context.Response.WriteFile(FileName);
  18.   }
  19.   else
  20.   {
  21.   context.Response.ContentType = "image/JPEG";
  22.   context.Response.WriteFile("/Content/Image/Forbidden.jpg");
  23.   }
  24.   }
  25.   }

解释一下,如果请求上下文的UrlReferrer或者Host都是null,那么返回一个404的图片,如果请求上下文的UrlReferrer或者Host不是null,但host不是我们自己的网站(这里因为是本地调试,所以网址是localhost),同样返回一个404的图片。

我们比较一下,先监控一下能获得正常图片的请求:

管道处理模型二(摘抄cainong2005博客)

再监控一下不能正常访问,只显示404图片:

管道处理模型二(摘抄cainong2005博客)

当然,Http请求是可以模拟的,只要模拟的到位,一样可以得到正确的图片。

 

二. Webform请求的HttpApplication众多事件流程图

管道处理模型二(摘抄cainong2005博客)管道处理模型二(摘抄cainong2005博客)管道处理模型二(摘抄cainong2005博客)

三.HttpModule和HttpHandler的区别

HttpModule:是任何一个Http请求都必须执行的东西,是附着在事件(Event)上的动作。

HttpHandler:任何一个请求一定有一个HttpHandler在处理,这个HttpHandler要么是aspx,要么是ashx,要么是mvc。

那么,什么场景用HttpModule,什么场景用HttpHandler?

1.session处理 : HttpModule

2.身份认证:HttpModule

3.权限检测:HttpModule

4.trace.axd查看追踪信息:HttpHandler

5.Outputcach输出缓存:HttpModule

6.config禁止下载:HttpHandler

7.cs代码不允许访问:HttpHandler

HttpModule适合处理全局的,因为任何请求都要经过它,任何请求都需要session,都需要身份认证,都需要权限检测,都需要缓存处理。

HttpHandler适合处理单一请求,查看追踪信息,config禁止下载,cs代码不允许访问这些都属于单一请求。

其实所有的东西HttpModule都可以做到,只是不适合而已。

四.路由、HttpHandler映射,哪个先执行?

用上面的,verify的例子,http://localhost:8090/handler/1.verify ,我们先在web.config中做了映射,所以它可以执行我们自定义的HttpHandler,输出显示验证码的图片。

如果url改成 http://localhost:8090/1.verify呢,找不到控制器。

管道处理模型二(摘抄cainong2005博客)

这个图说明,虽然我们给verify做了映射,但是路由在HttpHandler之前就执行了,即还没有到MapRequestHandler,就被拦截了,谁拦截的?PostResolveRequestCache。

管道处理模型二(摘抄cainong2005博客)

怎么做到的?要从UrlRoutingModule说起,用反编译工具打开UrlRoutingModule

管道处理模型二(摘抄cainong2005博客)

再看一下PostResolveRequestCache方法里面干了什么。

管道处理模型二(摘抄cainong2005博客)管道处理模型二(摘抄cainong2005博客)

那么MapRoute又是什么呢?用反编译工具看:

管道处理模型二(摘抄cainong2005博客)

回到刚才的 PostResolveRequestCache方法。

管道处理模型二(摘抄cainong2005博客)

RemapHandle是干什么的呢?解释一下 

管道处理模型二(摘抄cainong2005博客)

五.MVC路由以及和Webform的区别

那为什么aspx可以顺序执行下去,而MVC跳过去了呢?看看上面说到的GetRouteData方法,就是在这个方法里面,webform和mvc产生了分支。

管道处理模型二(摘抄cainong2005博客)管道处理模型二(摘抄cainong2005博客)

再看一个MVC总的流程图:

管道处理模型二(摘抄cainong2005博客)

管道处理模型二(摘抄cainong2005博客)

B2:用MapRoute来增加路由。

管道处理模型二(摘抄cainong2005博客)

并且把route放入RouteCollection中。route是什么?route的构造函数,参数分别是url和MvcRouteHandler,这里讲到B3了。

管道处理模型二(摘抄cainong2005博客)

MvcRouteHandler里面又是什么?

管道处理模型二(摘抄cainong2005博客)

B4:MvcRouteHandler可以通过GetHttpHandler方法得到一个HttpHandler,所以也可以说MvcRouteHandler负责生产IHttpHandler,如果不好理解,可以把MvcRouteHandler看成是HttpHandler。所以route的构造函数,就是传入了一个url和一个处理这个url的HttpHandler。这就和我们在webconfig文件中自定义的HttpHandler映射是一个道理,那里是什么后缀对应什么HttpHandler来处理(webform),这里是什么url对应什么HttpHandler来处理(mvc)。

管道处理模型二(摘抄cainong2005博客)

url和处理这个url的HttpHandler,它们二者的对应关系是怎么对应的?就是在RouteConfig中建立的:

管道处理模型二(摘抄cainong2005博客)

B5:所以RouteCollection里面有很多这样的route。

现在可以宏观的看这张mvc流程图了,先启动网站A1,然后进入Application_start(B1),执行Global(B2)中的RouteConfig,用routes.MapRoute注册了很多route,这些route保存了url和处理这些url的MvcRouteHandler(B3),然后这些MvcRouteHandler生产出HttpHandler(B4),将这些route放入RouteCollection(B5),好了 ,路由规则做好了,进入A2,22个事件依次执行(A3),执行到PostResolveRequestCache的时候,扩展了一个UrlRoutingModule(A4),UrlRoutingModule拿着url去在B5中已经准备好了的RouteCollection中去做匹配,找处理该url的MvcRouteHandler(A5),找到了MvcRouteHandler,然后把这个MvcRouteHandler生产的HttpHandler(mvc中就是MvcHandler)给context。

回头再看看PostResolveRequestCache方法:

管道处理模型二(摘抄cainong2005博客)

上一篇:HttpModule和静态类,多个请求共享相同的静态数据吗?


下一篇:IIS 7 Http Handler开发问题