• 第十三节:HttpHander扩展及应用(自定义扩展名、图片防盗链)


    一. 自定义扩展名

    1. 前言

       凡是实现了IHttpHandler接口的类均为Handler类,HttpHandler是一个HTTP请求的真正处理中心,在HttpHandler容器中,ASP.NET Framework才调用HttpHandler的ProcessRequest方法来对这个HTTP请求进行真正的处理,真正地对客户端请求的服务器页面做出编译和执行,并将处理过后的信息附加在HTTP请求信息流中再次返回到HttpModule中。

    2. 背景

       我们在日常开发中,也许会碰到一些这样的特殊需求,在路由规则之外,想给自己预留一个后门,进行一些小动作;或者想自定义一种特有的看起来很酷炫的后缀;或者默写后缀不想走MVC框架默认提供的处理流程,那么使用HttpHander进行扩展,再合适不过。

       下面我们先扩展一个后缀为 .ypf的处理请求,凡是该后缀的请求,统一显示验证码页面。

    3. 详细步骤

      ①. 新建一个类(ypfCode),实现IHttpHandler接口。

     1  /// <summary>
     2     ///这里自定义的handle为一般处理程序,实现了IHttpHandler接口
     3     ///IRequiresSessionState是为了使http请求具有会话状态的读写权限,即能操控: context.Session["CheckCode"] = code;
     4     /// </summary>
     5     public class ypfCode : IHttpHandler, IRequiresSessionState
     6     {
     7         /// <summary>
     8         /// 您将需要在网站的 Web.config 文件中配置此处理程序 
     9         /// 并向 IIS 注册它,然后才能使用它。有关详细信息,
    10         /// 请参阅以下链接: https://go.microsoft.com/?linkid=8101007
    11         /// </summary>
    12         #region IHttpHandler Members
    13 
    14         public bool IsReusable
    15         {
    16             // 如果无法为其他请求重用托管处理程序,则返回 false。
    17             // 如果按请求保留某些状态信息,则通常这将为 false。
    18             get { return true; }
    19         }
    20 
    21         public void ProcessRequest(HttpContext context)
    22         {
    23             //在此处写入您的处理程序实现。
    24             string code = "";
    25             Bitmap bitmap = VerifyCodeHelper.CreateVerifyCode(out code);
    26             context.Session["CheckCode"] = code;
    27             bitmap.Save(context.Response.OutputStream, ImageFormat.Gif);
    28             context.Response.ContentType = "image/gif";
    29         }
    30         #endregion
    31     }

      补充一个验证码实现类:

     1  public class VerifyCodeHelper
     2     {
     3         public static Bitmap CreateVerifyCode(out string code)
     4         {
     5             //建立Bitmap对象,绘图
     6             Bitmap bitmap = new Bitmap(200, 60);
     7             Graphics graph = Graphics.FromImage(bitmap);
     8             graph.FillRectangle(new SolidBrush(Color.White), 0, 0, 200, 60);
     9             Font font = new Font(FontFamily.GenericSerif, 48, FontStyle.Bold, GraphicsUnit.Pixel);
    10             Random r = new Random();
    11             string letters = "ABCDEFGHIJKLMNPQRSTUVWXYZ0123456789";
    12 
    13             StringBuilder sb = new StringBuilder();
    14 
    15             //添加随机的五个字母
    16             for (int x = 0; x < 5; x++)
    17             {
    18                 string letter = letters.Substring(r.Next(0, letters.Length - 1), 1);
    19                 sb.Append(letter);
    20                 graph.DrawString(letter, font, new SolidBrush(Color.Black), x * 38, r.Next(0, 15));
    21             }
    22             code = sb.ToString();
    23 
    24             //混淆背景
    25             Pen linePen = new Pen(new SolidBrush(Color.Black), 2);
    26             for (int x = 0; x < 6; x++)
    27                 graph.DrawLine(linePen, new Point(r.Next(0, 199), r.Next(0, 59)), new Point(r.Next(0, 199), r.Next(0, 59)));
    28             return bitmap;
    29         }
    30     } 
    View Code

      ②. 在Web.config文件中的 <system.webServer>→<handlers>下添加以下节点,表示以.ypf为后缀的请求统一由ypfCode处理,其中

       <add name="ypf" path="*.ypf" verb="*" type="Ypf.Web.Core.PipeLine.ypfCode,Ypf.Web.Core" />

        Ypf.Web.Core.PipeLine.ypfCode:表示该类的命名空间

        Ypf.Web.Core:表示该类所在库的程序集名称

     1  <!--VS2013及以后/IIS7.0之后的集成模式  需要添加下面的system.webServer节点-->
     2   <system.webServer>
     3     
     4     <!--1. 在此处配置modules-->
     5     <modules runAllManagedModulesForAllRequests="false">
     6       <!--1.1 runAllManagedModulesForAllRequests处理静态文件的请求-->
     7       <remove name="FormsAuthentication" />
     8       <!--1.2 优化网站性能,去掉不需要的module-->
     9       <remove name="RoleManager" />
    10       <remove name="FileAuthorization" />
    11       <remove name="UrlAuthorization" />
    12     </modules>
    13     <!--2. 在此处配置handlers-->
    14     <handlers>
    15       <!--2.1 优化网站性能,去掉不需要的module-->
    16       <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
    17       <remove name="OPTIONSVerbHandler" />
    18       <remove name="TRACEVerbHandler" />
    19       <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    20 
    21       <!--2.2 添加自定义handlers-->
    22       <!--2.2.1 后缀为ypf的请求 -->
    23       <add name="ypf" path="*.ypf" verb="*" type="Ypf.Web.Core.PipeLine.ypfCode,Ypf.Web.Core" />
    24 
    25       <!--2.2.2 图片处理请求 -->
    26       <!--方案一 逐个添加不同格式的图片   特别注意:不支持在一个path写多个扩展名-->
    27       <!--<add name="img" path="*.jpg" verb="*" type="Ypf.Web.Core.PipeLine.imgHandle,Ypf.Web.Core" />
    28       <add name="png" path="*.png" verb="*" type="Ypf.Web.Core.PipeLine.imgHandle,Ypf.Web.Core" />
    29       <add name="gif" path="*.gif" verb="*" type="Ypf.Web.Core.PipeLine.imgHandle,Ypf.Web.Core" />-->
    30       <!--方案二 通过HangerFactory来处理  特别注意:不支持在一个path写多个扩展名 -->
    31       <add name="img" path="*.jpg" verb="*" type="Ypf.Web.Core.PipeLine.ImageHandlerFactory,Ypf.Web.Core" />
    32       <add name="png" path="*.png" verb="*" type="Ypf.Web.Core.PipeLine.ImageHandlerFactory,Ypf.Web.Core" />
    33       <add name="gif" path="*.gif" verb="*" type="Ypf.Web.Core.PipeLine.ImageHandlerFactory,Ypf.Web.Core" />
    34 
    35     </handlers>
    36   </system.webServer>
    View Code

      ③. 由于本身框架本身已经有一套路由规则用来处理http请求,所以需要在RouteConfig中忽略该自定义Handle的规则,如下:

      routes.IgnoreRoute("MyTest/{*pathInfo}"); 表示MyTest/格式的请求不进行路由验证

      

      ④. 测试:http://localhost:7559/MyTest/xxx.ypf 均返回验证码图片

     

    二. 图片防盗链

    1. 什么是图片防盗链

      自己网站中展示的自己的图片通常是放在自己服务器上,很多无耻的网站获取到别人网站的图片地址,放到自己网站上,这就是图片盗链。

    图片被盗链损耗的是自己服务器的流量。

    2. 防盗链的代码实现原理

     当接受到一张图片请求的时候

     1. 判断该图片请求是从哪一个请求连接过来的(或者从哪一个页面连接过来的),如果为空,表示是一个单独的图片请求,肯定不该站内的,

     所以判断为盗链。两种判断方式如下

       a: context.Request.ServerVariables["HTTP_REFERER"]

       b: context.Request.UrlReferrer

     2. 如果上一个请求不为空,则判断上一个请求中是否含有该站的域名或ip地址,如果没有,则为非法请求,不是该站内的请求,

     所以判断为盗链。两种判断方法

       a:context.Request.UrlReferrer.Host.Contains("121.42.223.23")

       b:context.Request.ServerVariables["HTTP_REFERER"].Contains("121.42.223.23")

    3. 自定义hander进行处理

    ①. 自定义imgHandle,实现IHttpHandler接口

     1 /// <summary>
     2     /// 图片防盗链
     3     ///  该自定义handle用来处理各种获取图片的请求
     4     /// (这里处理 jpg gif png三种格式的图片)
     5     /// </summary>
     6     public class imgHandle : IHttpHandler
     7     {
     8    
     9         public bool IsReusable
    10         {
    11             // 如果无法为其他请求重用托管处理程序,则返回 false。
    12             // 如果按请求保留某些状态信息,则通常这将为 false。
    13             get { return true; }
    14         }
    15 
    16         public void ProcessRequest(HttpContext context)
    17         {
    18 
    19             //0.获取图片的返回类型
    20             string type = GetContentType(context.Request.Url.ToString());
    21 
    22             var beforeUrl = context.Request.ServerVariables["HTTP_REFERER"];
    23 
    24             //1. 如果请求的url为空,或者请求的主机部分为空,返回一张禁止倒链的图片
    25             if (context.Request.UrlReferrer == null || context.Request.UrlReferrer.Host == null)
    26             {
    27                 //context.Response.ContentType = "image/JPEG";
    28                 //context.Response.WriteFile("/Content/imageHandle/Forbidden.jpg");
    29 
    30                 context.Response.Write("您的请求是非法,请勿再试");
    31             }
    32             else
    33             {
    34                 //2. url不空,且包含自己主机域名,表示为自己网站的请求,显示正常图片
    35                 //正常发布的时候这里用域名或者ip,localhost为了本地调试
    36                 if (context.Request.UrlReferrer.Host.Contains("121.42.200.127"))
    37                 {
    38                     string FileName = context.Server.MapPath(context.Request.FilePath);
    39                     context.Response.ContentType = type;
    40                     context.Response.WriteFile(FileName);
    41                 }
    42                 else
    43                 {
    44                     //3. url不空,但不包含自己主机域名,表示该请求为盗链请求,返回一张禁止倒链的图片
    45                     //context.Response.ContentType = "image/JPEG";
    46                     //context.Response.WriteFile("/Content/imageHandle/Forbidden.jpg");
    47 
    48                     context.Response.Write("您的请求是非法,请勿再试");
    49                 }
    50 
    51             }
    52         }
    53 
    54         /// <summary>
    55         /// 将地址转换成图片返回值
    56         /// </summary>
    57         /// <param name="url"></param>
    58         /// <returns></returns>
    59         private static string GetContentType(string url)
    60         {
    61             switch (Path.GetExtension(url))
    62             {
    63                 case ".gif":
    64                     return "Image/gif";
    65                 case ".jpg":
    66                     return "Image/jpeg";
    67                 case ".png":
    68                     return "Image/png";
    69                 default:
    70                     break;
    71             }
    72             return null;
    73         }
    74 
    75     }

      扩展:也可以自定义handleFactory,实现IHttpHandlerFactory接口,在handleFactory中指定不同hander。

     1 /// <summary>
     2     /// 自定义的一个HandleFactory,用来指定不同的后缀调用不同的Handle
     3     /// 这里是一个ImageHandlerFactory,处理不同 图片后缀
     4     /// </summary>
     5     public class ImageHandlerFactory : IHttpHandlerFactory
     6     {
     7         public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
     8         {
     9             string path = context.Request.PhysicalPath;
    10             if (Path.GetExtension(path).Equals(".jpg"))
    11             {
    12                 return new imgHandle();
    13             }
    14             else if (Path.GetExtension(path).Equals(".png"))
    15             {
    16                 return new imgHandle();
    17             }
    18             else
    19             {
    20                 //这里可以继续扩展,这里测试不继续扩展了
    21                 return new imgHandle();
    22             }
    23 
    24         }
    25 
    26         public void ReleaseHandler(IHttpHandler handler)
    27         {
    28            
    29         }
    30     }
    View Code

    ②. 在Web.config文件中的 <system.webServer>→<handlers>下添加:

     <add name="img" path="*.jpg" verb="*" type="Ypf.Web.Core.PipeLine.imgHandle,Ypf.Web.Core" />

     <add name="png" path="*.png" verb="*" type="Ypf.Web.Core.PipeLine.imgHandle,Ypf.Web.Core" />

     <add name="gif" path="*.gif" verb="*" type="Ypf.Web.Core.PipeLine.imgHandle,Ypf.Web.Core" />

     1  <!--VS2013及以后/IIS7.0之后的集成模式  需要添加下面的system.webServer节点-->
     2   <system.webServer>
     3     
     4     <!--1. 在此处配置modules-->
     5     <modules runAllManagedModulesForAllRequests="false">
     6       <!--1.1 runAllManagedModulesForAllRequests处理静态文件的请求-->
     7       <remove name="FormsAuthentication" />
     8       <!--1.2 优化网站性能,去掉不需要的module-->
     9       <remove name="RoleManager" />
    10       <remove name="FileAuthorization" />
    11       <remove name="UrlAuthorization" />
    12     </modules>
    13     <!--2. 在此处配置handlers-->
    14     <handlers>
    15       <!--2.1 优化网站性能,去掉不需要的module-->
    16       <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
    17       <remove name="OPTIONSVerbHandler" />
    18       <remove name="TRACEVerbHandler" />
    19       <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    20 
    21       <!--2.2 添加自定义handlers-->
    22       <!--2.2.1 后缀为ypf的请求 -->
    23       <add name="ypf" path="*.ypf" verb="*" type="Ypf.Web.Core.PipeLine.ypfCode,Ypf.Web.Core" />
    24 
    25       <!--2.2.2 图片处理请求 -->
    26       <!--方案一 逐个添加不同格式的图片   特别注意:不支持在一个path写多个扩展名-->
    27       <add name="img" path="*.jpg" verb="*" type="Ypf.Web.Core.PipeLine.imgHandle,Ypf.Web.Core" />
    28       <add name="png" path="*.png" verb="*" type="Ypf.Web.Core.PipeLine.imgHandle,Ypf.Web.Core" />
    29       <add name="gif" path="*.gif" verb="*" type="Ypf.Web.Core.PipeLine.imgHandle,Ypf.Web.Core" />
    30       <!--方案二 通过HangerFactory来处理  特别注意:不支持在一个path写多个扩展名 -->
    31       <!--<add name="img" path="*.jpg" verb="*" type="Ypf.Web.Core.PipeLine.ImageHandlerFactory,Ypf.Web.Core" />
    32       <add name="png" path="*.png" verb="*" type="Ypf.Web.Core.PipeLine.ImageHandlerFactory,Ypf.Web.Core" />
    33       <add name="gif" path="*.gif" verb="*" type="Ypf.Web.Core.PipeLine.ImageHandlerFactory,Ypf.Web.Core" />-->
    34 
    35     </handlers>
    36   </system.webServer>
    View Code

    4. 代码测试

       新建一个Index页面,在该页面通过img标签直接链接到图片地址,显示图片,然后将该项目发布到测试服务器上。

     

     ①:访问地址:http://121.42.200.127:8099/Pipe/Index, 正常显示该页面中的图片, 表示该图片请求为站内正常的请求

     ②:访问地址:http://121.42.200.127:8099/Content/imageHandle/pipe1.jpg, 不能正常访问,表示该图片请求为盗链

  • 相关阅读:
    蚂蚁金服合作的RISE实验室到底有多牛?
    2016年全球IC设计大厂营收排名:高通稳居龙头
    2016年全球IC设计大厂营收排名:高通稳居龙头
    2016年全球IC设计大厂营收排名:高通稳居龙头
    2016年全球IC设计大厂营收排名:高通稳居龙头
    C++模板遇到iterator时候遇到的问题和解决方法
    C++模板遇到iterator时候遇到的问题和解决方法
    C++模板遇到iterator时候遇到的问题和解决方法
    $("div span")选取里的所有的元素
    ParseError: Unrecognised input. Possibly missing something
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/8037255.html
Copyright © 2020-2023  润新知