IHttpHandler 概述
可能和我一样,很多Asp.Net开发人员都有过Asp的背景,以至于我们在开发程序的时候,通常都是在“页面级”上思考,也就是说我们现在正在做的这个页面应该有什么样的功能,是进行一个问卷调查还是一个数据库查询等等。而很少在“请求级”思考,考虑有没有办法来通过编码的方式来操控一个Http请求。

实际上,Framework提供了一系列的接口和类,允许你对于Http请求进行编程,而实现这一操作的一个主要的接口,就是 IHttpHandler(另一个是IHttpModule)。

应该还记得第一节中我们提到过 ISAPI,它根据文件名后缀把不同的请求转交给不同的处理程序。但是仔细看看就会发现:几乎一大半的文件都交给 aspnet_isapi.dll 去处理了。很明显,aspnet_isapi.dll 不可能对每种文件采用同一种方式处理,那么 aspnet_isapi.dll 是如何更进一步处理不同的文件,交由谁去处理呢?为了搞清楚这个问题,我们需要打开机器上C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\ 目录下的web.config 文件。

NOTE:我查阅了很多资料,都说是在 machine.config 中,但实际上 v2.0.50727 下的machine.config中httpHandlers结点是这样的:<httpHandlers />,并没有给出详细的处理程序,在Web.config中才能看到。而v1.1.4322 下的machine.config中却有。

找到httpHandlers结点,应该可以看到如下这样的代码(做了省略):

<httpHandlers>

... ...
<add path="*.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True" />

<add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True" />
   <add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True" />
   <add path="*.asax" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />
<add path="*.ascx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />
   <add path="*.config" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />
   <add path="*.cs" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />
   <add path="*" verb="GET,HEAD,POST" type="System.Web.DefaultHttpHandler" validate="True" />
   ... ...
</httpHandlers>

可以看到,在<httpHandlers>结点中将不同的文件类型映射给不同的Handler去处理,对于.aspx来说,是由System.Web.UI.PageHandlerFactory来处理。而对于.cs来说,是由System.Web.HttpForbiddenHandler 处理,从ForbiddenHandler名字中出现的Forbidden (翻译过来是“禁止”)可以看出,这个Handler可以避免我们的源码被看到。

NOTE:System.Web.UI.PageHandlerFactory 是一个IHttpHandlerFactory,而不是一个单一的HttpHandler,IHttpHandlerFactory用来做什么后面会说明。

上面列出的是.Net Framework在处理Http请求时的所采用的默认Handler。而如果我们要用编程的方式来操控一个Http请求,我们就需要实现IHttpHandler接口,来定制我们自己的需求。

IHttpHandler的定义是这样的:

public interface IHttpHandler{

void ProcessRequest(HttpContext context);

bool IsReusable { get; }

}

由上面可以看出IHttpHandler要求实现一个方法和一个属性。其中 ProcessRequest,从名字(处理请求)看就知道这里应该放置我们处理请求的主要代码。

IsReusable属性,MSDN上是这样解释的:获取一个值,该值指示其他请求是否可以使用 IHttpHandler 实例。也就是说后继的Http请求是不是可以继续使用实现了该接口的类的实例,一般来说,我把它设置成true。

那么实现此接口的类形式应该是这样的:

public class CustomHandler : IHttpHandler{

public void ProcessRequest(HttpContext context)  {

// 处理请求的代码

}

public bool IsReusable {

get { return true; }

}

}

而为了能使用这个自定义的HttpHandler,我们需要在应用程序目录下的Web.config中注册它。

<system.web>

<httpHandlers>

<add path="*.jpg" verb="*" type="MyNameSpace.MyClass, MyDllName" />

</httpHandlers>

</system.web>

应该发现这与之前在C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\目录下web.config中看到的几乎完全一样。这里,path指的是请求的文件名称,可以使用通配符扩大范围,也可以明确指定这个handler仅用于处理某个特定的文件(比如说:filename.aspx)的请求。verb指的是请求此文件的方式,可以是post或get,用*代表所有访问方式。type属性由“,”分隔成两部分,第一部分是实现了接口的类名,第二部分是位于Bin目录下的编译过的程序集名称。

NOTE:如果你新建一个项目,并且在项目下创建HandlerTest.cs,然后让站点引用该项目,那么在生成解决方案的时候会自动将编译好的.dll文件添到Bin目录中。

NOTE:MyDll只写程序集名,不要加后面的.dll。

使用HttpHandler实现图片防盗链
有了之前这么多的准备知识,实现现在的目标就容易得多了:

NOTE:这个例子,以及下面的一个例子均来自于《Maximizing ASP.NET Real World, Object-Oriented Development》一书:

Step.1:创建文件 CustomHandler.cs,代码如下:
using System;

using System.Web;

namespace CustomHandler{

public class JpgHandler : IHttpHandler{

public void ProcessRequest(HttpContext context){

// 获取文件服务器端物理路径

string FileName = context.Server.MapPath(context.Request.FilePath);

// 如果UrlReferrer为空,则显示一张默认的禁止盗链的图片

if (context.Request.UrlReferrer.Host == null){

context.Response.ContentType = "image/JPEG";

context.Response.WriteFile("/error.jpg");

}else{

// 如果 UrlReferrer中不包含自己站点主机域名,则显示一张默认的禁止盗链的图片

if (context.Request.UrlReferrer.Host.IndexOf("yourdomain.com") > 0){

context.Response.ContentType = "image/JPEG";

context.Response.WriteFile(FileName);

}else{

context.Response.ContentType = "image/JPEG";

context.Response.WriteFile("/error.jpg");

}

}

}

public bool IsReusable{

get{ return true; }

}

}

}

Step.2 编译这个文件
csc /t:library /r:System.Web.dll CustomHandler.cs

Step.3 将编译好的 CustomHandler.dll 拷贝到站点的 Bin 目录下。
Step.4 在Web.Config 中注册这个Handler。
  <system.web>

<httpHandlers>

<add path="*.jpg" verb="*" type="CustomHandler.JpgHandler, CustomHandler" />

</httpHandlers>

</system.web>

OK,诸位可以按步骤自行测试一下,这里就不赘述了。

通过IhttpHandler实现图片验证码
也可以在一个.ashx文件中实现IHttpHandler,而不是采用这种提前编译的方式。

Step.1 打开Vs2005,“添加新项”,“一般处理程序”。新建文件后,VS会自动在文件中添加如下的代码:
<%@ WebHandler Language="C#" class="Handler" %>

using System;

using System.Web;

public class Handler : IHttpHandler {

public void ProcessRequest (HttpContext context) {

context.Response.ContentType = "text/plain";

context.Response.Write("Hello World");

}

public bool IsReusable {

get {

return false;

}

}

}

Step.2 将代码改写成如下所示:
<%@ WebHandler Language="C#" class="Handler" %>

using System;

using System.Drawing;

using System.Drawing.Imaging;

using System.Text;

using System.Web;

using System.Web.SessionState;

public class Handler : IHttpHandler, IRequiresSessionState {

public void ProcessRequest(HttpContext context) {

context.Response.ContentType = "image/gif";

//建立Bitmap对象,绘图

Bitmap basemap = new Bitmap(200, 60);

Graphics graph = Graphics.FromImage(basemap);

graph.FillRectangle(new SolidBrush(Color.White), 0, 0, 200, 60);

Font font = new Font(FontFamily.GenericSerif, 48, FontStyle.Bold, GraphicsUnit.Pixel);

Random r = new Random();

string letters = "ABCDEFGHIJKLMNPQRSTUVWXYZ";

string letter;

StringBuilder s = new StringBuilder();

//添加随机的五个字母

for (int x = 0; x < 5; x++) {

letter = letters.Substring(r.Next(0, letters.Length - 1), 1);

s.Append(letter);

graph.DrawString(letter, font, new SolidBrush(Color.Black), x * 38, r.Next(0, 15));

}

//混淆背景

Pen linePen = new Pen(new SolidBrush(Color.Black), 2);

for (int x = 0; x < 6; x++)

graph.DrawLine(linePen, new Point(r.Next(0, 199), r.Next(0, 59)), new Point(r.Next(0, 199), r.Next(0, 59)));

//将图片保存到输出流中

basemap.Save(context.Response.OutputStream, ImageFormat.Gif);

context.Session["CheckCode"] = s.ToString();   //如果没有实现IRequiresSessionState,则这里会出错,也无法生成图片

context.Response.End();

}

public bool IsReusable {

get { return true; }

}

}

需要特别注意的是,Handler类不仅需要实现 IHttpHandler接口(这个显然),为了在这个Handler类中使用SessionState,还需要实现IRequiresSessionState接口,对于这个接口,MSDN的解释是这样的:Specifies that the target HTTP handler requires read and write access to session-state values. This is a marker interface and has no methods.(翻译过来是:指定当前Http Handler需要对SessionState值的读写访问权。这是一个标记接口,没有任何方法)。

而实际上,IRequiresSessionState的接口定义是这样的:

public interface IRequiresSessionState

{

}

可见,这个接口没有任何需要实现的方法或属性,大家只要记得:如果想在HttpHandler中使用SessionState,必须实现这个接口,实际上也就是在类的标头将这个接口加进去。

Step.3 新建一个ImageCode.aspx页面,在HTML代码中写下:
     <img src="Handler.ashx" alt="图片验证码" />

OK,在浏览器中打开ImageCode.aspx,应该可以看到如下所示:

利用HttpHandler创建自定义后缀Rss源
RSS如今已经可以说是随处可见,而RSS的实现方式,通常是在一个.aspx的CodeBehind文件中写一个XML文件,然后加载到Response的OutputStream中, Rss源通常是Rss.aspx这种形式的。通过第一章学到的ISAPI的知识,再结合本章学到的关于HttpHandler的知识,很容易想到:我们可以自定一个以 .rss 作为后缀名的文件来实现 Rss 源,比如说Article.rss。现在我们就一步步来实现它:

NOTE:关于RSS的更多内容,可以参阅我编译的《在Web站点中创建和使用RSS源》。本文不再解释Rss是什么,如何创建Rss源,为了文章的独立性,仅给出创建过程。

Step.1 创建范例数据库
Create Table RssSample

(

SampleId     Int Identity(1,1)       Not Null,

Title            Varchar(100)         Not Null Constraint uq_Title Unique,

Author           Varchar(50)               Not Null,

PubDate          DateTime             Not Null Default GetDate(),

[Description]    Varchar(500)         Not Null,

Link         Varchar(150)         Not Null

Constraint pk_RssSample Primary Key(SampleId)

)

-- 插入范例数据

Insert Into RssSample(Title, Author, [Description], Link)

Values('标题1', '作者1', '文章摘要1', 'http://127.0.0.1/#' )

-- 省略 ....

Step.2 建立站点,在App_Code目录下建立RssFeedsLib.cs文件。
using System;

using System.Data;

using System.Data.SqlClient;

using System.IO;

using System.Web;

using System.Xml;

using System.Text;

namespace RssFeadsLib {

public class RssGenerator {

public static string GetRSS() {

MemoryStream ms = new MemoryStream();

XmlTextWriter writer = new XmlTextWriter(ms, null);

SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=Sample;User ID=sa;Password=sa");      //修改这里成你的数据库连接

SqlCommand cmd = new SqlCommand("select * from RssSample order by pubdate desc", conn);

conn.Open();

SqlDataReader reader = cmd.ExecuteReader();

writer.WriteStartElement("rss");

writer.WriteAttributeString("version", "2.0");

writer.WriteStartElement("channel");

// Channel 下的结点静态写入

writer.WriteElementString("title", "TraceFact.Net 技术文章");

writer.WriteElementString("link", "http://www.tracefact.net");

writer.WriteElementString("description", "Dedicated to asp.net...");

writer.WriteElementString("copyright", "Copyright (C) 2007");

writer.WriteElementString("generator", "My RSS Generator");

// Item 结点从数据库读取

while (reader.Read()) {

writer.WriteStartElement("item");

writer.WriteElementString("author", reader.GetString(reader.GetOrdinal("Author")));

writer.WriteElementString("title",                 reader.GetString(reader.GetOrdinal("title")));

writer.WriteElementString("link", reader.GetString(reader.GetOrdinal("Link")));

writer.WriteElementString("description", reader.GetString(reader.GetOrdinal("Description")));

writer.WriteElementString("pubDate", reader.GetDateTime(reader.GetOrdinal("PubDate")).ToString(@"ddd, dd MMM yyyy 12:00:00 tt "));

writer.WriteEndElement();

}

writer.WriteEndElement();

writer.WriteEndElement();

reader.Close();

conn.Close();

writer.BaseStream.Flush();

writer.Flush();

ms.Flush();

// 将流转换成String并返回

byte[] data = new byte[ms.Length];

ms.Seek(0, SeekOrigin.Begin);

ms.Read(data, 0, data.Length);

ms.Close();

return UTF8Encoding.UTF8.GetString(data);

}

}

}

Step.3 创建可以处理 .rss 后缀名的 RssHandler
我们在这个 RssFeedsLib命名空间下,再添加一个类,这个类用于处理对 .rss 后缀名文件的Http请求。

public class RSSHandler:IHttpHandler{

public bool IsReusable

{

get {return false;}

}

public void ProcessRequest(HttpContext context){

context.Response.ContentType = "text/xml";

string str = RssGenerator.GetRSS();

context.Response.Write(str);

}

}

Step.4 在Web.config中进行配置
<httpHandlers>

<add path="*.rss" type="RssFeadsLib.RSSHandler" verb="GET" />

</httpHandlers>

NOTE:因为这个类和命名空间位于App_Code中,这里就不需要再手动编译RssFeadsLib.cs然后将编译好的.dll应用程序集放到Bin目录中了。至于为什么可以这样,将会在 《Asp.Net 构架与安全机制 Part.5 – 页面生存周期与编译模型》中解释。

Step.5 在IIS 对ISAPI进行设置。
应该还记得在Part.1中如何在IIS中设置ISAPI来进行文件与处理程序映射:

1.     打开IIS,选择本范例所用的站点,右键,选择“属性”。

2.     选择“主目录”选项卡,点击“配置...”按钮。

3.     点击“添加”,设置“可执行文件”为“C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll”,设置“扩展名”为“.rss”,点“确定”。

4.     注意,不要勾选“检查文件是否存在”复选框,这样不用创建文件,只要在地址栏输入任意以.rss后缀结尾的文件名,均会交由上面创建的Handler去处理,而不管这个文件是否存在,也不管请求的是Article.rss还是Sample.rss。

进行了这些设置以后,现在IIS就知道如何去处理对.rss后缀名文件的请求了。

Step.6 测试范例
这个时候,随便打开一个页面,比如空白的Default.aspx,然后我们在地址栏将文件改为:Article.rss(改成abc.rss也是一样),敲回车,应该可以看到如下的画面。

IHttpHandlerFactory 概述
现在假设我们有这样的需求,我们不仅想要处理 .rss 后缀名,还想要能够处理 .atom后缀名,假设处理atom的类命名为AtomHandler,那么我们的Web.config该如何设置呢?我想应该是这样的:

<httpHandlers>

<add path="*.rss" type="RssFeadsLib.RSSHandler" verb="GET" />

<add path="*.atom" type="RssFeadsLib.AtomHandler" verb="GET" />

</httpHandlers>

如果我们有很多个HttpHandler分别映射不同后缀名的请求,这样我们的Web.config会变得很冗长,或者,我们只有在程序运行时才能确切地知道使用哪个Handler,这个时候,可以考虑实现 IHttpHandlerFactory来完成这一过程。

IHttpHandlerFactory的定义是这样的:

public interface IHttpHandlerFactory{

IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated);

void ReleaseHandler(IHttpHandler handler);

}

可见,需要实现两个方法,分别是 GetHandler() 和 ReleaseHandler()。

l       GetHandler(),返回实现了IHttpHandler接口的类的实例。

l       ReleaseHandler(),使得Factory可以重复使用一个已经存在的Handler实例。

对于上面 .atom 和 .rss 的问题,我们可以这样来实现 IHttpHandlerFactory接口:

class HandlerFactory:IHttpHandlerFactory{

public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated){

string path = context.Request.PhysicalPath;

if (Path.GetExtension(path) == ".rss"){

return new RSSHandler();

}

if (Path.GetExtension(path) == ".atom"){

return new ATOMHandler();

}

return null;

}

public void ReleaseHandler(IHttpHandler handler){

}

}

这时,在Web.Config 中<system.web>节点下进行如下设置即可:

<httpHandlers>

<add path="*.rss,*.atom" type=" RssFeadsLib.HandlerFactory" verb="GET" />

</httpHandlers>

但是,这不能简化IIS中ISAPI的设置,还是需要手动去对.rss和.atom分别设置。

总结
在本文中,我们首先讨论了aspnet_isapi.dll 如何将对不同后缀名文件的请求分发给相应的处理程序,如何查看Framework默认的处理程序Handler。

然后,我们通过三个实例,图片防盗链、图片验证码、处理自定义后缀名请求,详细讲解了IHttpHandler的实现方法和使用过程。

最后,我向大家概要地介绍了IHttpHandlerFactory接口。

希望这篇文章能给你带来帮助。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jxooooxl/archive/2007/10/27/1847221.aspx

转载于:https://www.cnblogs.com/sntetwt/archive/2011/04/09/2010792.html

IHttpHandler 概述相关推荐

  1. IHttpHandler 介绍演示(from 张子阳)

    Http Handler 介绍 引言 在 Part.1 Http请求处理流程 一 文中,我们了解了Http请求的处理过程以及其它一些运作原理.我们知道Http管道中有两个可用接口,一个是IHttpHa ...

  2. 利用 IHttpHandler 自定义 HTTP 处理程序

    本文内容 引入 IHttpHandler 概述 演示创建自定义 HTTP 处理程序 创建自定义 HTTP 处理程序 映射文件扩展名 测试自定义 HTTP 处理程序 参考资料 引入 当新建一个名为 We ...

  3. Asp.Net 构架(Http Handler 介绍) - Part.2

    Asp.Net 构架(Http Handler 介绍) - Part.2 引言 在 Part.1 Http请求处理流程 一文中,我们了解了Http请求的处理过程以及其它一些运作原理.我们知道Http管 ...

  4. Http Handler 介绍(转)

    转自:http://www.tracefact.net/Asp-Net-Architecture/Introduction-to-Http-Handler.aspx Http Handler 介绍 引 ...

  5. ASP.NET页面与IIS底层交互和工作原理详解(一)

    第一回: 引言 我查阅过不少Asp.Net的书籍,发现大多数作者都是站在一个比较高的层次上讲解Asp.Net.他们耐心.细致地告诉你如何一步步拖放控件.设置控件属性.编写CodeBehind代码,以实 ...

  6. Http Handler 介绍

    引言 在 Part.1 Http请求处理流程 一文中,我们了解了Http请求的处理过程以及其它一些运作原理.我们知道Http管道中有两个可用接口,一个是IHttpHandler,一个是IHttpMod ...

  7. C#开发技术点说明-四种简单的排序算法,AJAX,Http Module,Http 请求处理流

    我觉得如果想成为一名优秀的开发者,不仅要积极学习时下流行的新技术,比如WCF.Asp.Net MVC.AJAX等,熟练应用一些已经比较成熟的技术,比如Asp.Net.WinForm.还应该有着牢固的计 ...

  8. ASP.NET 应用程序生命周期概述

    本主题概述应用程序生命周期,列出重要的生命周期事件,并描述如何编写适合应用程序生命周期的代码.在 ASP.NET 中,若要对 ASP.NET 应用程序进行初始化并使它处理请求,必须执行一些处理步骤.此 ...

  9. IIS 5.0 和 6.0 的 ASP.NET 应用程序生命周期概述

    http://msdn.microsoft.com/zh-cn/library/ms178473(v=VS.100).aspx 在 ASP.NET 中,若要对 ASP.NET 应用程序进行初始化并使它 ...

最新文章

  1. 脚本中export不起作用的原因分析
  2. mysql存储netcdf数据_关于NetCDF与HDF5存储科学数据的观点?
  3. 2018 年,我们该如何使用 JavaScript?
  4. java 初始化log4j_java – log4j:WARN请正确初始化log4j系统
  5. 制作css开关,纯css实现开关效果
  6. [css] 使用css实现霓虹灯效果
  7. LeetCode 20. 有效的括号(栈)
  8. gitbook mysql_使用Gitbook做笔记
  9. TIOBE 2021年3月程序语言排名 - python要超越Java排第二了?
  10. JS 浏览器扩展storage
  11. java动态删除属性值_JavaBean动态添加删除属性
  12. Memcached 及 Redis 架构分析和比较
  13. Oracle中的SAVEPOINT
  14. 360企业版使用感受
  15. 数据结构 二叉树的建立,遍历
  16. jQuery+bootstrap实现美化警告/确认/提示对话框插件
  17. 计算机视觉论文-2021-06-01
  18. h5打开android的app的具体页面,通过H5打开app,进入到指定页面
  19. 2022智源大会议程公开 | 预训练大模型论坛
  20. centos6安装wget

热门文章

  1. three相机在模型上_基于 three.js 的 3D 粒子动效实现
  2. 黑龙江科技大学计算机类分数线,2019年黑龙江科技大学优势专业排名及分数线...
  3. 机器人最大的人类士人禾力积木_开化县华埠镇中心小学:积木机器人好玩儿~~...
  4. mongodb java 日志分析_记一次log4j与mongodb集成引发的问题分析
  5. java calendar与date_Java中date和calendar的用法
  6. C++在堆区创建数组
  7. html表格中加入斜线,在HTML中显示带斜线的表格
  8. oracle oud什么意思,oracle 在linux上,如何使用oud工具恢復truncate 表中的记录? 超急!请帮帮忙...
  9. Python Qt GUI设计:窗口布局管理方法【强化】(基础篇—6)
  10. 和12岁小同志搞创客开发:如何选择合适的传感器?