【分析最原始验证码生成】HTTP请求处理程序
我们知道,在ASP.NET中,所有的请求都要进过HttpApplication的处理管道,具体请参见DebugLZQ前面的博文。在服务器处理请求的过程中,实际的请求处理时通过处理程序来完成的,在HttpApplication的第11个事件(PreRequestHandlerExecute)之后,将会调用处理程序来处理请求。
这是很有道理的,因为请求都要经过这个处理管道,但是,请求的内容是多种多样的,应该对每种不同的请求映射不同的处理程序,这个ASP.NET处理的基本思想。正是由于请求的多种多样,因此,在HttpApplication的处理管道中,适合处理针对所有请求的通用处理,比如检查当前请求的用户身份等,并不适合直接处理情求的内容并返回处理的结果。针对不同请求的不同处理,在ASP.NET中通过各种处理程序来分别进行处理。通常情况下,根据请求的扩展名来确定适用的处理程序,根据常见的请求类型,在ASP.NET中已经与定义了许多的处理程序。
请求的真正处理是在处理程序这个环节,那么,HttpApplication的作用是什么呢?我们可以将它看作请求到达处理程序和离开处理程序的一个管道,这个管道提供了统一处理所有请求的机制,使得我们可以在请求被真正处理之前和处理之后进行预处理和处理后的工作,在有些网站处理技术中,被称为过滤器(Filter)。ASP.NET通过大量的HttpApplication事件,这些事件按照固定的次序依次处罚,使得我们可以方便地开发出针对请求不同处理环节的过滤器。
处理程序则负责完成实际的请求处理工作,对于网站开发程序员来说,大多数的开发工作是围绕着处理程序展开的。实际上,接触到HttpApplication事件处理的时候并不多,处理程序在不同的网站开发技术中,有着不同的名称,在ASP.NET中,称为HttpHandler。
在ASP.NET中,所有的处理程序类必须实现IHttpHandler接口或者实现 IHttpAsyncHandler接口,这两个接口的区别是前者是一个同步接口,后者是一个异步处理模式的接口。这两个接口都定义在命名空间System.Web下。
IHttpHandler的定义如下(大家都很熟悉吧!!!):
· ProcessRequest是这个接口的主要方法,接受一个HttpContext类型的请求上下文对象,通过这个对象,处理程序可以得到关于处理请求所需的信息,通过这个参数的Response属性可以得到管理回应的对象,用以向客户端返回服务器处理的结果。
· IsResuable属性表示当这个处理程序对象在使用之后,是否还可以被缓存起来,在以后的请求处理中再次使用,这个属性主要用来配合处理程序工厂使用。
处理程序是ASP.NET网站中处理请求的基本单位,在默认情况下,处理程序中,甚至不能使用会话状态,这样可以提高网站处理的速度。对于需要读写会话状态的处理程序,必须实现一个特定的接口IRequiresSessionState,这个接口定义在命名空间System.Web.SessionState中,其中没有定义任何成员,所以实现这个接口并不需要在类中增加任何成员。与此类似,同样定义在这个命名空间下的接口 IReadOnlySessionState 也没有定义任何成员,用来标识只需读取会话状态的处理程序。
这种没有任何成员的接口,通常被称为标记接口,由于在.NET中类只有单继承,但是可以实现多个接口,所以在.NET开发早期的时候出现过一些通过标记接口来表示类的某些特征的开发技巧。但是.NET平台上提供了一个更加直接简单的技术来解决这种问题,这就是标签(Attribute),所以,这种用法昙花一现,现在很少出现。在ASP.NET开发中,这是仅有的一例。
每一种处理程序用来处理一类的请求,不同的请求类别通过请求的扩展名来进行区分,处理程序与请求之间的匹配关系在网站的配置文件web.config中通过配置参数进行设置。system.web配置元素的子元素 httpHandlers 用来配置网站所使用的处理程序。httpHandlers元素可以包含三种子元素:add、remove、clear。
add子元素有三个必选的属性,作用如下:
· verb 通过一个逗号(,)分隔的HTTP请求类型列表来表示处理请求的类型,例如GET,POST等;使用型号(*)表示处理所有类型的请求。
· path 通过一个固定的URL路径或者一个使用型号(*)的通配符来匹配请求的URL,例如,使用*.aspx表示这个处理程序将处理所有扩展名为aspx的请求。
· type 处理程序 的类型名称,或者是处理程序工厂的类型名称,这个类型必须是类型的全名,如果类定义在一个命名空间中,那么必须包含这个命名空间,如果定义在一个私有的应用程序集中,那么必须在类名之后,通过附加一个逗号(,)分隔的程序集名称,这个程序集的扩展名可以省略
validate为可选的属性,如果设置为false,那么ASP.NET在第一次匹配的请求调用之前将不会试图加载这个类。
在网站应用程序运行的时候,实际得到的配置文件来自于系统能够的machine.config,系统的web.config 和网站自身的web.config合并!(记住哦,O(∩_∩)O)
在web.config中ASP.NET已经预先配置了57中处理程序的映射,程序员可以通过处理程序接口扩展自定义的处理程序。
博友声音:好了,说了这么多来个例子来说明下吧,学以致用嘛!!
DebugLZQ:OK,马上开始。DebugLZQ就使用最原始的处理程序生成验证码!当然用一般处理程序会简化很多,废话,一般处理程序就是用来简化处理程序的!!!!还有其他很多处理程序,页面处理程序、Web服务处理程序、MVC处理程序、资源处理程序。。。。其实都是对处理程序的简化。
完成这个处理程序,需要以下几个步骤:
1)创建一个类库项目 MyHandler,这个项目的默认命名空间也是 MyHandler
2)类库项目MyHandler中添加一个新类ValidateCodeHandler,实现IHttpHandler接口,为了在处理程序中使用Session状态管理,同时实现IRequiresSessionState接口。
3)在ProcessRequest方法中完成验证码生成的操场。
4)在网站项目中引用类库项目。
5)在网站配置文件web.config中注册这个处理程序。
6)在需要验证码的页面上使用处理程序生产的验证码。
下面给出处理程序生成验证码的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyHandler
{
public class ValidateCodeHandler : System.Web.IHttpHandler,
System.Web.SessionState.IRequiresSessionState
{
private static System.Random random = new Random();
public void ProcessRequest(System.Web.HttpContext context)
{
context.Response.ContentType = "image/jpeg";
System.Drawing.Image image = new System.Drawing.Bitmap(60, 30);
// 生成随机数
int code = random.Next(1000, 10000);
string codeString = code.ToString();
// 使用会话状态
context.Session["Code"] = codeString;
using (System.Drawing.Graphics g
= System.Drawing.Graphics.FromImage(image))
{
g.Clear(System.Drawing.Color.WhiteSmoke);
System.Drawing.StringFormat sf
= new System.Drawing.StringFormat();
sf.Alignment = System.Drawing.StringAlignment.Center;
sf.LineAlignment = System.Drawing.StringAlignment.Center;
g.DrawString(
codeString,
new System.Drawing.Font("Arial", 14),
System.Drawing.Brushes.Blue,
new System.Drawing.RectangleF(0, 0,
image.Width, image.Height),
sf
);
}
context.Response.ContentType = "image/jpeg";
image.Save(
context.Response.OutputStream,
System.Drawing.Imaging.ImageFormat.Jpeg
);
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
(简单的GDI+代码,这个不是重点,但是DebugLZQ还是奉上!)
处理程序在网站中得配置,如下(说明:在web.config <configuration><system.web>下添加配置):
<!-- 添加这个配置节-->
<httpHandlers>
<add verb="*" path="*.vc" type="MyHandler.ValidateCodeHandler,MyHandler"/>
</httpHandlers>
好了,下面是如何使用。很简单,在页面中需要验证码的地方添加类似下面的代码:
<asp:Image ID="Image1" runat="server" ImageUrl="a.vc"/>
DebugLZQ的必要的说明,其实并不存在"a.vc"这个东东,取得是其扩展名。
好了,看下效果:
好了,完成!
博友心声:DebugLZQ,何必这么麻烦呢?!为了生成验证码,我们紧紧需要在网站中得增加一个一般处理程序,然后,在ProcessRequest方法中实现功能就可以了。这样,原来的1、2、4、5步都可以省略了!!!!!
DebugLZQ:是的,是这样子的,谢谢你的意见!DebugLZQ的写博文的初衷是让各位博友理解其中最为本质、最为原始的原理,请多多支持啊(O(∩_∩)O哈哈~)
【请点击下面的绿色通道关注DebugLZQ,与DebugLZQ共同学习进步!】