65.9K
CodeProject 正在变化。 阅读更多。
Home

两个拦截器:HttpModule 和 HttpHandler

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (105投票s)

2008年11月12日

CPOL

5分钟阅读

viewsIcon

445586

downloadIcon

3894

两个拦截器:HttpModule 和 HttpHandler

目录

引言

很多时候,我们希望在请求到达 IIS 资源之前实现预处理逻辑。例如,您可能希望应用安全机制、URL 重写、过滤请求中的某些内容等。ASP.NET 提供了两种拦截方式:HttpModuleHttpHandler。本文将对此进行探讨。

问题

很多时候,我们需要在页面被请求之前注入某种逻辑。一些常用的预处理逻辑包括统计计数器、URL 重写、身份验证/授权等等。我们可以在代码隐藏中完成这些操作,但这可能会导致很多复杂性和代码混乱。代码隐藏无法解决问题,因为在某些实现中,例如授权,我们希望在逻辑到达资源之前执行。ASP.NET 提供了两种在请求管道中注入逻辑的方式:HttpHandlersHttpModules

HttpHandler - 基于扩展名的预处理器

HttpHandler 帮助我们根据请求文件名的扩展名注入预处理逻辑。因此,当请求页面时,HttpHandler 根据文件名扩展名和动词执行。例如,您可以从下面的图中看到我们如何将不同的 Handler 映射到文件扩展名。我们还可以将一个 Handler 映射到多个文件扩展名。例如,当任何客户端请求扩展名为“GIF”和“JPEG”的文件时,handler3 的预处理逻辑将执行。

HttpModule - 基于事件的预处理器

HttpModule 是一种基于事件的方法,用于在任何资源被请求之前注入预处理逻辑。当任何客户端发送资源请求时,请求管道会发出大量事件,如下图所示。

下面是事件的详细说明。我们只是从 这里 粘贴了这些内容。

  • BeginRequest:请求已开始。如果您需要在请求开始时执行某些操作(例如,在每个页面的顶部显示广告横幅),请同步此事件。
  • AuthenticateRequest:如果您想插入自己的自定义身份验证方案(例如,在数据库中查找用户以验证密码),请构建一个同步此事件的模块,并以您想要的方式对用户进行身份验证。
  • AuthorizeRequest:此事件用于内部实现授权机制(例如,将访问控制列表 (ACL) 存储在数据库而不是文件系统中)。虽然您可以覆盖此事件,但通常没有太多好的理由这样做。
  • PreRequestHandlerExecute:此事件在 HTTP Handler 执行之前发生。
  • PostRequestHandlerExecute:此事件在 HTTP Handler 执行之后发生。
  • EndRequest:请求已完成。您可能希望构建一个调试模块,该模块在整个请求过程中收集信息,然后将信息写入页面。

我们可以使用 HttpModules 注册这些事件。因此,当请求管道执行时,根据注册的事件,将处理来自模块的逻辑。

Handler 和 Module 的整体图景

现在我们已经了解了基本知识,让我们来理解 Microsoft 对 Handler 和 Module 的定义,以获得整体的认识。

参考:INFO:ASP.NET HTTP Modules and HTTP Handlers Overview

“Modules 在 Handler 执行之前和之后被调用。Modules 使开发人员能够拦截、参与或修改每个单独的请求。Handlers 用于处理单个终结点请求。Handlers 使 ASP.NET 框架能够处理应用程序内的单个 HTTP URL 或一组 URL 扩展。与 modules 不同,只有一个 handler 用于处理一个请求。”

实现 HttpHandlers 的步骤

步骤 1

HttpHandlers 只是实现了预处理逻辑的类。所以第一步是创建一个类项目,引用 System.Web 命名空间,并实现 IHttpHandler 接口,如下面的代码片段所示。IHttpHandler 接口有两个需要实现的方法:一个是 ProcessRequest,另一个是 IsResuable。在 ProcessRequest 方法中,我们只是将 URL 写入文件并在浏览器中显示。我们已经操作了上下文响应对象以将显示发送到浏览器。

using System;
using System.Web;
using System.IO;
namespace MyPipeLine
{
public class clsMyHandler : IHttpHandler
{
public void ProcessRequest(System.Web.HttpContext context)
{
context.Response.Write("The page request is " + context.Request.RawUrl.ToString());
StreamWriter sw = new StreamWriter(@"C:\requestLog.txt",true);
sw.WriteLine("Page requested at " + DateTime.Now.ToString() + 
			context.Request.RawUrl); sw.Close();
}
public bool IsReusable
{
get
{
return true;
}
}
}

第二步

在第二步中,我们需要在 HttpHandlers 标签中添加一个条目。在标签中,我们需要指定请求的哪种扩展名将调用我们的类。

<system.web>
<httpHandlers>
<add verb="*" path="*.Shiv,*.Koirala" type="MyPipeLine.clsMyHandler, MyPipeLine"/>
</httpHandlers>
</system.web>

完成后,请求扩展名为“Shiv”的页面,您应该会看到如下所示的显示。发生的情况是,当 IIS 检测到请求是针对“.shiv”页面扩展名时,它会调用 clsMyHandler 类的预处理逻辑。

实现 HttpModule 的步骤

步骤 1

正如之前讨论的,HttpModule 是一个事件预处理器。所以第一步是实现 IHttpModule 并注册此模块应订阅的必要事件。例如,在此示例中,我们注册了 BeginRequestEndRequest 事件。在这些事件中,我们只是将一个条目写入日志文件。

public class clsMyModule : IHttpModule
{
public clsMyModule()
{}
public void Init(HttpApplication objApplication)
{
// Register event handler of the pipe line
objApplication.BeginRequest += new EventHandler(this.context_BeginRequest);
objApplication.EndRequest += new EventHandler(this.context_EndRequest);
}
public void Dispose()
{
}
public void context_EndRequest(object sender, EventArgs e)
{
StreamWriter sw = new StreamWriter(@"C:\requestLog.txt",true);
sw.WriteLine("End Request called at " + DateTime.Now.ToString()); sw.Close();
}
public void context_BeginRequest(object sender, EventArgs e)
{
StreamWriter sw = new StreamWriter(@"C:\requestLog.txt",true);
sw.WriteLine("Begin request called at " + DateTime.Now.ToString()); sw.Close();
}
}

第二步

我们需要在 HttpModule 标签中输入这些模块条目,如以下代码片段所示。

<httpModules>
<add name="clsMyModule" type="MyPipeLine.clsMyModule, MyPipeLine"/>
</httpModules>

最终输出

如果您运行代码,您应该会在 *RequestLog.txt* 中看到类似这样的内容。上面的示例不是非常实用。但它将帮助我们理解基本原理。

Begin request called at 11/12/2008 6:32:00 PM
End Request called at 11/12/2008 6:32:00 PM
Begin request called at 11/12/2008 6:32:03 PM
End Request called at 11/12/2008 6:32:03 PM
Begin request called at 11/12/2008 6:32:06 PM
End Request called at 11/12/2008 6:32:06 PM
Begin request called at 11/12/2008 8:36:04 PM
End Request called at 11/12/2008 8:36:04 PM
Begin request called at 11/12/2008 8:37:06 PM
End Request called at 11/12/2008 8:37:06 PM
Begin request called at 11/12/2008 8:37:09 PM
End Request called at 11/12/2008 8:37:09 PM
Begin request called at 11/12/2008 8:37:38 PM
Page requested at 11/12/2008 8:37:38 PM/WebSiteHandlerDemo/Articles.shiv
End Request called at 11/12/2008 8:37:38 PM

参考

如需进一步阅读,请观看以下面试准备视频和分步视频系列。

© . All rights reserved.