知识大全 HttpModule与HttpHandler详解

Posted 事件

篇首语:时危见臣节,世乱识忠良。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 HttpModule与HttpHandler详解相关的知识,希望对你有一定的参考价值。

HttpModule与HttpHandler详解  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  ASP NET对请求处理的过程

  当请求一个* aspx文件的时候 这个请求会被inetinfo exe进程截获 它判断文件的后缀(aspx)之后 将这个请求转交给 ASPNET_ISAPI dll ASPNET_ISAPI dll会通过管道(Http PipeLine)将请求发送给ASPNET_WP exe进程 在ASPNET_WP exe进程中通过HttpRuntime来处理这个请求 处理完毕将结果返回客户端

  inetinfo exe进程 是服务的进程 IIS服务和ASPNET_ISAPI DLL都寄存在此进程中

  ASPNET_ISAPI DLL 是处理 aspx文件的win 组件 其实IIS服务器是只能识l文件的 当IIS服务器发现被请求的文件是 aspx文件时 IIS服务器将其交给aspnet_isapi dll来处理

  aspnet_wp exe进程 ASP NET框架进程 提运行的托管环境的CLR(公共语言运行时)就是寄存在此进程中

  ASP NET Framework处理一个Http Request的流程

  HttpRequest >inetinfo exe >ASPNET_ISAPI dll >ASPNET_WP exe >HttpRuntime >HttpApplication Factory >HttpApplication >HttpModule >HttpHandler Factory >HttpHandler >HttpHandler ProcessRequest()

  ASP NET请求处理过程是基于管道模型的 这个管道模型是由多个HttpModule和HttpHandler组成 ASP NET 把请求依次传递给管道中各个HttpModule 最终被HttpHandler处理 处理完成后 再次经过管道中的HTTP模块 把结果返回给客户端 我们可以在每个HttpModule中都可以干预请求的处理过程

  注意 在请求的处理过程中 只能调用一个HttpHandler 但可以调用多个HttpModule

  当请求到达HttpModule的时候 系统还没有对这个请求真正处理 但是我们可以在这个请求传递到处理中心(HttpHandler)之前附加一些其它信息 或者截获的这个请求并作一些额外的工作 也或者终止请求等 在HttpHandler处理完请求之后 我们可以再在相应的HttpModule中把请求处理的结果进行再次加工返回客户端

  HttpModule

  HTTP模块是实现了System Web IModule接口的类

  IHttpModule接口的声明

  public interface IHttpModule

  

  void Init (HttpApplication context);

  void Dispose ();

  

  Init 方法 系统初始化的时候自动调用 这个方法允许HTTP模块向HttpApplication 对象中的事件注册自己的事件处理程序

  Dispose方法 这个方法给予HTTP模块在对象被垃圾收集之前执行清理的机会 此方法一般无需编写代码

  HTTP模块可以向System Web HttpApplication对象注册下面一系列事件

  AcquireRequestState 当ASP NET运行时准备好接收当前HTTP请求的对话状态的时候引发这个事件

  AuthenticateRequest 当ASP NET 运行时准备验证用户身份的时候引发这个事件

  AuthorizeRequest 当ASP NET运行时准备授权用户访问资源的时候引发这个事件

  BeginRequest 当ASP NET运行时接收到新的HTTP请求的时候引发这个事件

  Disposed 当ASP NET完成HTTP请求的处理过程时引发这个事件

  EndRequest 把响应内容发送到客户端之前引发这个事件

  Error 在处理HTTP请求的过程中出现未处理异常的时候引发这个事件

  PostRequestHandlerExecute 在HTTP处理程序结束执行的时候引发这个事件

  PreRequestHandlerExecute 在ASP NET开始执行HTTP请求的处理程序之前引发这个事件 在这个事件之后 ASP NET 把该请求转发给适当的HTTP处理程序

  PreSendRequestContent 在ASP NET把响应内容发送到客户端之前引发这个事件 这个事件允许我们在内容到达客户端之前改变响应内容 我们可以使用这个事件给页面输出添加用于所有页面的内容 例如通用菜单 头信息或脚信息

  PreSendRequestHeaders 在ASP NET把HTTP响应头信息发送给客户端之前引发这个事件 在头信息到达客户端之前 这个事件允许我们改变它的内容 我们可以使用这个事件在头信息中添加cookie和自定义数据

  ReleaseRequestState 当ASP NET结束所搜有的请求处理程序执行的时候引发这个事件

  ResolveRequestCache 我们引发这个事件来决定是否可以使用从输出缓冲返回的内容来结束请求 这依赖于Web应用程序的输出缓冲时怎样设置的

  UpdateRequestCache 当ASP NET完成了当前的HTTP请求的处理 并且输出内容已经准备好添加给输出缓冲的时候 引发这个事件 这依赖于Web应用程序的输出缓冲是如何设置的

  BeginRequest和PreRequestHandlerExecute之间的事件是在服务器执行HttpHandler处理之前触发

  PostRequestHandlerExecute和PreSendRequestContent之间的事件是在服务器执行Handler处理之后触发

  下面我们看一下如何使用HttpModule来实现我们日常的应用

  HttpModule通过在某些事件中注册 把自己插入ASP NET请求处理管道 当这些事件发生的时候 ASP NET调用对相应的HTTP模块 这样该模块就能处理请求了

   向每个页面动态添加一些备注或说明性的文字

  有的网站每一个页面都会弹出一个广告或在每个页面都以注释形式(<! >)加入网站的版权信息 如果在每个页面教编写这样的JS代码的话 对于大一点的网站 这种JS代码的编写与维护可是一个很繁琐枯燥的工作

  有了HttpModule我们就可以很简单地解决这个问题了 HttpModule是客户端发出请求到客户端接收到服务器响应之间的一段必经之路 我们完全可以在服务器处理完请求之后 并在向客户端发送响应文本之前这段时机 把这段注释文字添加到页面文本之后 这样 每一个页面请求都会被附加上这段注释文字

  这段代码究竟该在哪个事件里实现呢? PostRequestHandlerExecute和PreSendRequestContent之间的任何一个事件都可以 但我比较喜欢在EndRequest事件里编写代码

  第一步 创建一个类库ClassLibrary

  第二步 编写一个类实现IHttpModule接口

  class TestModule:IHttpModule

  

  public void Dispose()

  

  

  public void Init(HttpApplication context)

  

  

  

  第三步 在Init事件中注册EndRequest事件 并实现事件处理方法

  class TestModule:IHttpModule

  

  public void Dispose()

  public void Init(HttpApplication context)

  

  context EndRequest += new EventHandler(context_EndRequest);

  

  void context_EndRequest(object sender EventArgs e)

  

  HttpApplication ha = (HttpApplication)sender;

  ha Response Write( <! 这是每个页面都会动态生成的文字 grayworm > );

  

  

  第四步 在Web Conofig中注册一下这个HttpModule模块

  <Modules>

  <add name= TestModule type= ClassLibrary TestModule ClassLibrary ></add>

  </Modules>

  name 模块名称 一般是类名

  type 有两部分组成 前半部分是命名空间和类名组成的全名 后半部分是程序集名称 如果类是直接放在App_Code文件夹中 那程序名称是App_Code

  这样在Web站点是添加该类库的引用后 运行每个页面 会发现其源文件中都会加入 <! 这是每个页面都会动态生成的文字 grayworm > 这句话 同样的方法你也可以在其中加入JS代码

   身份检查

  大家在作登录时 登录成功后 一般要把用户名放在Session中保存 在其它每一个页面的Page_Load事件中都检查Session中是否存在用户名 如果不存在就说明用户未登录 就不让其访问其中的内容

  在比较大的程序中 这种做法实在是太笨拙 因为你几乎要在每一个页面中都加入检测Session的代码 导致难以开发和维护 下面我们看看如何使用HttpModule来减少我们的工作量

  由于在这里我们要用到Session中的内容 我们只能在AcquireRequestState和PreRequestHandlerExecute事件中编写代码 因为在HttpModule中只有这两事件中可以访问Session 这里我们选择PreRequestHandlerExecute事件编写代码

  第一步 创建一个类库ClassLibrary

  第二步 编写一个类实现IHttpModule接口

  class TestModule:IHttpModule

  

  public void Dispose()

  

  

  public void Init(HttpApplication context)

  

  

  

  第三步 在Init事件中注册PreRequestHandlerExecute事件 并实现事件处理方法

  class AuthenticModule:IHttpModule

  

  public void Dispose()

  public void Init(HttpApplication context)

  

  context PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);

  

  void context_PreRequestHandlerExecute(object sender EventArgs e)

  

  HttpApplication ha = (HttpApplication)sender;

  string path = ha Context Request Url ToString();

  int n = path ToLower() IndexOf( Login aspx );

  if (n == ) //是否是登录页面 不是登录页面的话则进入

  

  if (ha Context Session[ user ] == null) //是否Session中有用户名 若是空的话 转向登录页

  

  ha Context Response Redirect( Login aspx?source= + path);

  

  

  

  

  第四步 在Login aspx页面的 登录 按钮中加入下面代码

  protected void Button _Click(object sender EventArgs e)

  

  if(true)    //判断用户名密码是否正确

  

  if (Request QueryString[ source ] != null)

  

  string s = Request QueryString[ source ] ToLower() ToString();   //取出从哪个页面转来的

  Session[ user ] = txtUID Text;

  Response Redirect(s); //转到用户想去的页面

  

  else

  

  Response Redirect( main aspx );    //默认转向main aspx

  

  

  

  第五步 在Web Conofig中注册一下这个HttpModule模块

  <Modules>

  <add name= TestModule type= ClassLibrary TestModule ClassLibrary ></add>

  </Modules>

   多模块的操作

  如果定义了多个HttpModule 在nfig文件中引入自定义HttpModule的顺序就决定了多个自定义HttpModule在处理一个HTTP请求的接管顺序

  HttpHandler

  HttpHandler是HTTP请求的处理中心 真正地对客户端请求的服务器页面做出编译和执行 并将处理过后的信息附加在HTTP请求信息流中再次返回到HttpModule中

  HttpHandler与HttpModule不同 一旦定义了自己的HttpHandler类 那么它对系统的HttpHandler的关系将是 覆蓋 关系

  IHttpHandler接口声明

  public interface IHttpHandler

  

  bool IsReusable get;

  public void ProcessRequest(HttpContext context); //请求处理函数

  

  示例 把硬盘上的图片以流的方式写在页面上

  class TestHandler : IHttpHandler

  

  public void ProcessRequest(HttpContext context)

  

  FileStream fs = new FileStream(context Server MapPath( worm jpg ) FileMode Open);

  byte[] b = new byte[fs Length];

  fs Read(b (int)fs Length);

  fs Close();

  context Response OutputStream Write(b b Length);

  

  public bool IsReusable

  

  get

  

  return true;

  

  

  

  Web Config配置文件

  <Handlers>

  <add verb= * path= * type= ClassLibrary TestHandler ClassLibrary ></add>

  </Handlers>

  Verb属性 指定了处理程序支持的HTTP动作 *-支持所有的HTTP动作; GET -支持Get操作; POST -支持Post操作; GET POST -支持两种操作

  Path属性 指定了需要调用处理程序的路径和文件名(可以包含通配符) * * aspx showImage aspx test aspx test aspx

  Type属性 用名字空间 类名称和程序集名称的组合形式指定处理程序或处理程序工厂的实际类型 ASP NET运行时首先搜索bin目录中的DLL 接着在GAC中搜索

  这样程序运行的效果是该网站的任何一个页面都会显示worm jpg图片 如何只让一个页面(default aspx)执行HttpHandler 中的ProcessRequest方法呢?最简单的办法是在Web Config文件中把path配置信息设为default aspx

  根据这个例子大家可以考虑一下如何编写 验证码 了

  IHttpHandler工厂

  IHttpHandlerFactory的作用是对IHttpHandler进行管理 工厂的作用请见ml

  IHttpHandlerFactory接口的声明

  public interface IHttpHandlerFactory

  

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

  void ReleaseHandler (IHttpHandler handler);

  

  GetHandler返回实现IHttpHandler接口的类的实例 ReleaseHandler使工厂可以重用现有的处理程序实例

  示例 两个用IHttpHandlerFactory来实现对不同HttpHandler的调用

  有两个HttpHandler 将图片显示在页面上的HttpHandler和生成验证码的Handler

  //将图片显示在页面上的Handler

  class TestHandler : IHttpHandler

  

  public void ProcessRequest(HttpContext context)

  

  FileStream fs = new FileStream(context Server MapPath( worm jpg ) FileMode Open);

  byte[] b = new byte[fs Length];

  fs Read(b (int)fs Length);

  fs Close();

  context Response OutputStream Write(b b Length);

  

  public bool IsReusable

  

  get

  

  return true;

  

  

  

  //生成验证码的Handler

  class CodeHandler:IHttpHandler

  

  public bool IsReusable

  

  get

  

  return true;

  

  

  public void ProcessRequest(HttpContext context)

  

  Image b = new Bitmap( );

  Graphics g = Graphics FromImage(b);

  SolidBrush sb = new SolidBrush(Color White);

  Font f = new Font( 宋体 );

  string str = ;

  Random r = new Random();

  for (int i = ; i < ; i++)

  

  str += r Next( );

  

  g DrawString(str f sb );

  b Save(context Response OutputStream System Drawing Imaging ImageFormat Jpeg);

  

  

  IHttpHandler工厂

  class TestHandlerFactory : IHttpHandlerFactory

  

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

  

  string fname = url Substring(url IndexOf( / ) + );

  while (fname IndexOf( / ) != )

  fname = fname Substring(fname IndexOf( / ) + );

  string cname = fname Substring( fname IndexOf( ));

  string className = ;

  className = ClassLibrary CodeHandler ;

  object h = null;

  try

  

  //h = new TestHandler();

  h = Activator CreateInstance(Type GetType(className));

  

  catch (Exception e)

  

  throw new HttpException( 工厂不能为类型 + cname + 创建实例 e);

  

  return (IHttpHandler)h;

  

  public void ReleaseHandler(IHttpHandler handler)

  

  

  (车延禄)

  配置文件

  <Handlers>

  <add verb= * path= default aspx default aspx type= ClassLibrary TestHandlerFactory ClassLibrary ></add>

  </Handlers>

  这样TestHandlerFactory就会根据请求的不同页面执行不同的HttpHandler处理程序了

  HttpHandler使用会话

  如果要在处理程序中使用Session 那必须把该HttpHandler实现IRequiresSessionState接口 IRequiresSessionState接口是个空接口 它没有抽象方法 只是一个标记 此处就不作例子验证了

cha138/Article/program/net/201311/12275

相关参考

知识大全 顺序与回传详解[1]

ASP.NET页面事件:顺序与回传详解[1]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  一初

知识大全 顺序与回传详解[2]

ASP.NET页面事件:顺序与回传详解[2]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  四保

知识大全 JavaBean与MBean详解

JavaBean与MBean详解  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!    首先从Mod

知识大全 内存屏障与JVM并发详解

深入Java底层:内存屏障与JVM并发详解  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  内存屏

知识大全 js replace 与replaceall实例用法详解

这篇文章介绍了jsreplace与replaceall实例用法详解有需要的朋友可以参考一下   stringObjreplace(rgExpreplaceText)参数stringObj必选

知识大全 Delphi与SQL Server存储过程编程详解

Delphi与SQLServer存储过程编程详解  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  

知识大全 使用GruntJS链接与压缩多个JavaScript文件过程详解

使用GruntJS链接与压缩多个JavaScript文件过程详解  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起

知识大全 .NET的动态编译与WS服务调用详解

.NET的动态编译与WS服务调用详解  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!这篇文章介绍了N

知识大全 VB.NET与WEB服务器通讯过程详解

VB.NET与WEB服务器通讯过程详解  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  WebRe

知识大全 求一位大神口述详解一下可好

begoingto与well+动原的区别!求一位大神口述详解一下可好!begoingto与will的几点区别begoingto与will的几点区别:1.begoingto表示近期、眼下就要发生的事情,