昨天粗略讲了一下IHttpHandler接口的作用和动态给图片添加水印的处理,如果对这些不太清除的朋友,建议看看这篇《IHttpHandler的妙用(1):给图片添加水印》: http://blog.csdn.net/zhoufoxcn/archive/2008/01/10/2033530.aspx
昨天也提到了IHttpHandler接口主要有一个IsReusable属性和一个Proce***equest方法,利用这个方法我们可以处理很多事情的,昨天我们利用了这个方法给图片动态添加了水印,今天我再来展示另一种用法。
大家查看一个msdn,可以看到它的声明如下:
Visual Basic(声明)
Sub Proce***equest ( _
context As HttpContext _
)
Visual Basic(用法)
Dim instance As IHttpHandler
Dim context As HttpContext
instance.Proce***equest(context)
C#
void Proce***equest (
HttpContext context
)
Sub Proce***equest ( _
context As HttpContext _
)
Visual Basic(用法)
Dim instance As IHttpHandler
Dim context As HttpContext
instance.Proce***equest(context)
C#
void Proce***equest (
HttpContext context
)
注意这个HttpContext对象,它提供对用于为 HTTP 请求提供服务的内部服务器对象(如 Request、Response、Session 和 Server)的引用。
有了它我们就方便多了,因为我们的下载资源一般都会有一个下载介绍(假设为details.aspx?id=***),用户查看介绍之后,如果愿意下载,就会点击下载链接,这个链接也是一个页面(假设为download.aspx?id=***),我们就可以得出结论,只要是用户通过我们的网站下载这些资源,那么在下载资源之前访问那个页面(简称前导页,下同)一定是details.aspx,因此我们就可以得出结论只要是下载之前的前导页不是details.aspx这个页面,那个这个下载请求一定是别的网站盗链(其实还可以放宽一点,在下载之前的前导页一定是本站的页面,也还可以要求更紧一点,下载之前访问的页面的id值一定要与下载的id值一致,这就看大家的实际要求了)!
有了这个推论之后,我们就可以动手写代码了:
using
System;
using System.IO;
using System.Web;
///
/// 说明:DownloadHandler是一个防盗链的类,它可以防止本站资源被别的网站盗用
/// 作者:周公
/// 日期:2008-1-11
/// 首发地址: http://blog.csdn.net/zhoufoxcn
///
public class DownloadHandler:IHttpHandler
{
public DownloadHandler()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
#region IHttpHandler 成员
///
/// 指示IHttpHandler 实例是否可再次使用
///
public bool IsReusable
{
get { return true ; }
}
///
/// 处理请求的方法
///
/// 它提供对用于为 HTTP 请求提供服务的内部服务器对象(如 Request、Response、Session 和 Server)的引用。
public void Proce***equest(HttpContext context)
{
Uri referrerUri = context.Request.UrlReferrer; // 获取下载之前访问的那个页面的uri
Uri currentUri = context.Request.Url;
if (referrerUri == null ) // 没有前导页,直接访问下载页
{
// 输出提示,可以根据自身要求完善此处代码
context.Response.Write( " 请不要盗链本站资源,请从首页访问。首页 " );
return ;
}
#region 判断前导页是否位于本站可以用此段代码
// if (referrerUri.Host == currentUri.Host) // 前导页和当前请求页位于同一个主机
// {
// // 用户是通过正常路径访问的,向用户提供下载文件
// // 实际情况是根据id从数据库找到文件的物理路径,然后输出
// // 为了简单代码,仅仅演示流程,这里我直接输出了文件
// // 周公注。2008-1-11
// // 获取请求的物理文件路径
// WriteFile(context);
// }
// else
// {
// // 输出提示,可以根据自身要求完善此处代码
// context.Response.Write("请不要盗链本站资源,请从首页访问。首页");
// }
#endregion
#region 判断前导页是否是我们的介绍页面
string referrerPage = referrerUri.LocalPath.Substring(referrerUri.LocalPath.LastIndexOf( ' / ' ) + 1 );
if (referrerPage == " Details.aspx " ) // 如果前导页是我们的介绍页面
{
// 用户是通过正常路径访问的,向用户提供下载文件
// 实际情况是根据id从数据库找到文件的物理路径,然后输出
// 为了简单代码,仅仅演示流程,这里我直接输出了文件
// 周公注。2008-1-11
// 获取请求的物理文件路径
WriteFile(context);
}
else
{
// 输出提示,可以根据自身要求完善此处代码
context.Response.Write( " 请不要盗链本站资源,请从首页访问。首页 " );
}
#endregion
}
private void WriteFile(HttpContext context)
{
// 用户是通过正常路径访问的,向用户提供下载文件
// 实际情况是根据id从数据库找到文件的物理路径,然后输出
// 为了简单代码,仅仅演示流程,这里我直接输出了文件
// 周公注。2008-1-11
// 获取请求的物理文件路径
string path = context.Request.PhysicalPath;
// 注意这里rar文件的ContentType是application/octet-stream
// 不同格式文件的contentType有可能不同
context.Response.ContentType = " application/octet-stream " ;
context.Response.WriteFile(path);
}
#endregion
}
using System.IO;
using System.Web;
///
/// 说明:DownloadHandler是一个防盗链的类,它可以防止本站资源被别的网站盗用
/// 作者:周公
/// 日期:2008-1-11
/// 首发地址: http://blog.csdn.net/zhoufoxcn
///
public class DownloadHandler:IHttpHandler
{
public DownloadHandler()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
#region IHttpHandler 成员
///
/// 指示IHttpHandler 实例是否可再次使用
///
public bool IsReusable
{
get { return true ; }
}
///
/// 处理请求的方法
///
/// 它提供对用于为 HTTP 请求提供服务的内部服务器对象(如 Request、Response、Session 和 Server)的引用。
public void Proce***equest(HttpContext context)
{
Uri referrerUri = context.Request.UrlReferrer; // 获取下载之前访问的那个页面的uri
Uri currentUri = context.Request.Url;
if (referrerUri == null ) // 没有前导页,直接访问下载页
{
// 输出提示,可以根据自身要求完善此处代码
context.Response.Write( " 请不要盗链本站资源,请从首页访问。首页 " );
return ;
}
#region 判断前导页是否位于本站可以用此段代码
// if (referrerUri.Host == currentUri.Host) // 前导页和当前请求页位于同一个主机
// {
// // 用户是通过正常路径访问的,向用户提供下载文件
// // 实际情况是根据id从数据库找到文件的物理路径,然后输出
// // 为了简单代码,仅仅演示流程,这里我直接输出了文件
// // 周公注。2008-1-11
// // 获取请求的物理文件路径
// WriteFile(context);
// }
// else
// {
// // 输出提示,可以根据自身要求完善此处代码
// context.Response.Write("请不要盗链本站资源,请从首页访问。首页");
// }
#endregion
#region 判断前导页是否是我们的介绍页面
string referrerPage = referrerUri.LocalPath.Substring(referrerUri.LocalPath.LastIndexOf( ' / ' ) + 1 );
if (referrerPage == " Details.aspx " ) // 如果前导页是我们的介绍页面
{
// 用户是通过正常路径访问的,向用户提供下载文件
// 实际情况是根据id从数据库找到文件的物理路径,然后输出
// 为了简单代码,仅仅演示流程,这里我直接输出了文件
// 周公注。2008-1-11
// 获取请求的物理文件路径
WriteFile(context);
}
else
{
// 输出提示,可以根据自身要求完善此处代码
context.Response.Write( " 请不要盗链本站资源,请从首页访问。首页 " );
}
#endregion
}
private void WriteFile(HttpContext context)
{
// 用户是通过正常路径访问的,向用户提供下载文件
// 实际情况是根据id从数据库找到文件的物理路径,然后输出
// 为了简单代码,仅仅演示流程,这里我直接输出了文件
// 周公注。2008-1-11
// 获取请求的物理文件路径
string path = context.Request.PhysicalPath;
// 注意这里rar文件的ContentType是application/octet-stream
// 不同格式文件的contentType有可能不同
context.Response.ContentType = " application/octet-stream " ;
context.Response.WriteFile(path);
}
#endregion
}
对web.config的配置:
xml version="1.0"
?>
< configuration >
< appSettings >
< add key ="WaterMark" value ="http://blog.csdn.net/zhoufoxcn" />
< add key ="Font-Size" value ="72" />
appSettings >
< connectionStrings />
< system .web >
< compilation debug ="true" />
< authentication mode ="Windows" />
< httpHandlers >
< add path ="UploadImages/*.jpg" verb ="*" type ="ImageHandler" />
< add path ="*.zip" verb ="*" type ="DownloadHandler" />
< add path ="*.rar" verb ="*" type ="DownloadHandler" />
< add path ="*.iso" verb ="*" type ="DownloadHandler" />
httpHandlers >
system.web >
configuration >
< configuration >
< appSettings >
< add key ="WaterMark" value ="http://blog.csdn.net/zhoufoxcn" />
< add key ="Font-Size" value ="72" />
appSettings >
< connectionStrings />
< system .web >
< compilation debug ="true" />
< authentication mode ="Windows" />
< httpHandlers >
< add path ="UploadImages/*.jpg" verb ="*" type ="ImageHandler" />
< add path ="*.zip" verb ="*" type ="DownloadHandler" />
< add path ="*.rar" verb ="*" type ="DownloadHandler" />
< add path ="*.iso" verb ="*" type ="DownloadHandler" />
httpHandlers >
system.web >
configuration >
前导页(Details.aspx):
<%
@ Page Language
=
"
C#
"
AutoEventWireup
=
"
true
"
CodeFile
=
"
Details.aspx.cs
"
Inherits
=
"
Details
"
%>
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head runat ="server" >
< title > 无标题页 title >
head >
< body >
< form id ="form1" runat ="server" >
< div >
< a href ="Download.aspx?id=1" > 下载 a >
div >
form >
body >
html >
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head runat ="server" >
< title > 无标题页 title >
head >
< body >
< form id ="form1" runat ="server" >
< div >
< a href ="Download.aspx?id=1" > 下载 a >
div >
form >
body >
html >
下载页没有什么html代码,主要是后台代码。下载页后台代码(Download.aspx.cs):
using
System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class Download : System.Web.UI.Page
{
protected void Page_Load( object sender, EventArgs e)
{
if ( ! Page.IsPostBack)
{
CheckUser();
// 实际情况是根据id从数据库找到文件的物理路径,然后输出
// 为了简单代码,仅仅演示流程,这里我直接输出了文件
// 周公注。2008-1-11
// 首发地址: http://blog.csdn.net/zhoufoxcn
Response.Redirect( " download/demo.rar " );//这里就会交给DownloadHanddler处理了
}
}
// 检查用户登录等信息
private void CheckUser()
{
// 仅仅演示,具体代码根据具体要求编写
// 比如用户没有登录如何处理,用户没有下载权限如何处理等
return ;
}
}
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class Download : System.Web.UI.Page
{
protected void Page_Load( object sender, EventArgs e)
{
if ( ! Page.IsPostBack)
{
CheckUser();
// 实际情况是根据id从数据库找到文件的物理路径,然后输出
// 为了简单代码,仅仅演示流程,这里我直接输出了文件
// 周公注。2008-1-11
// 首发地址: http://blog.csdn.net/zhoufoxcn
Response.Redirect( " download/demo.rar " );//这里就会交给DownloadHanddler处理了
}
}
// 检查用户登录等信息
private void CheckUser()
{
// 仅仅演示,具体代码根据具体要求编写
// 比如用户没有登录如何处理,用户没有下载权限如何处理等
return ;
}
}
正常流程截图:
(一)先打开介绍页面:
(二)点击下载链接进入下载页面:
此时出现文件保存对话框,情况正常。
(一)先打开介绍页面:
(二)点击下载链接进入下载页面:
此时出现文件保存对话框,情况正常。
再看盗链情况(非正常情况):
(一)打开首页(非前导页,跳过这一步也没有关系)
(二)直接访问下载页面或者直接访问下载文件的实际url地址:
此时出现了我们自定义的错误提示,甚至地址栏上都出现了该文件的物理地址,可是就是没有办法下载,此时就算是利用迅雷等下载软件,下载到的也是一个无效的文件,如图:
这样就达到我们的目地了,不是通过正常途径来下载是没有办法下载到他需要的文件的。
(一)打开首页(非前导页,跳过这一步也没有关系)
(二)直接访问下载页面或者直接访问下载文件的实际url地址:
此时出现了我们自定义的错误提示,甚至地址栏上都出现了该文件的物理地址,可是就是没有办法下载,此时就算是利用迅雷等下载软件,下载到的也是一个无效的文件,如图:
这样就达到我们的目地了,不是通过正常途径来下载是没有办法下载到他需要的文件的。
顺便说一下,写作本文时我是边编写代码边测试的(本博客原创的代码都是如此,测试通过之后方才发表,所以一般不会有什么问题,如果你学习的过程中发现有任何错误,请仔细检查你的代码,因为各人本地环境不同,出错原因各异,恕本人不一一指出你代码的错误之处)。