管道处理模型二

管道处理模型一(下称《模型一》)是本篇的基础,不妨先看一下。

一.Httphandler:

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

<body>
    <form id="form1" runat="server">
        <div>
            This is MyWebForm
        </div>
    </form>
</body>

 运行结果:


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

    public partial class MyWebForm : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }
    }

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


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

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


它是在哪里配置的呢?

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


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


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


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

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


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


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


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

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


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


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


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

4.忽略路由:


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



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

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

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


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

       public ViewResult Handler()
        {
            IHttpHandler handler = base.HttpContext.Handler;
            ViewBag.HandlerName = handler.GetType().ToString();
            ViewBag.Url = Request.Url.AbsoluteUri;
            return View();
        }

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

@{
    ViewBag.Title = "Handler";
}

<h2>Handler</h2>
<p>@ViewBag.HandlerName</p>
<p>@ViewBag.Url</p>
<p>@Html.Image("/Content/Image/liuyan.jpg", "liuyan图片", "柳岩", new { id = "image" })</p>

运行一下,显示如图:


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


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


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

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

        public void ProcessRequest(HttpContext context)
        {
            // 如果UrlReferrer为空,则显示一张默认的禁止盗链的图片
            if (context.Request.UrlReferrer == null || context.Request.UrlReferrer.Host == null)
            {
                context.Response.ContentType = "image/JPEG";
                context.Response.WriteFile("/Content/Image/Forbidden.jpg");
            }
            else
            {
                // 如果 UrlReferrer中不包含自己站点主机域名,则显示一张默认的禁止盗链的图片
                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");
                }
            }
        }

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

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


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


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


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


三.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呢,找不到控制器。


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


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


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


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


回到刚才的 PostResolveRequestCache方法。


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


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

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


再看一个MVC总的流程图:



B2:用MapRoute来增加路由。


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


MvcRouteHandler里面又是什么?


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


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


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方法:


猜你喜欢

转载自blog.csdn.net/cainong2005/article/details/80160812
今日推荐