两个拦截器:HttpModule 和 HttpHandler






4.91/5 (105投票s)
两个拦截器:HttpModule 和 HttpHandler
目录
- 引言
- 问题
- HttpHandler - 基于扩展名的预处理器
- HttpModule - 基于事件的预处理器
- Handler 和 Module 的整体图景
- 实现 HttpHandlers 的步骤
- 实现 HttpModule 的步骤
- 最终输出
- 参考
引言
很多时候,我们希望在请求到达 IIS 资源之前实现预处理逻辑。例如,您可能希望应用安全机制、URL 重写、过滤请求中的某些内容等。ASP.NET 提供了两种拦截方式:HttpModule
和 HttpHandler
。本文将对此进行探讨。
问题
很多时候,我们需要在页面被请求之前注入某种逻辑。一些常用的预处理逻辑包括统计计数器、URL 重写、身份验证/授权等等。我们可以在代码隐藏中完成这些操作,但这可能会导致很多复杂性和代码混乱。代码隐藏无法解决问题,因为在某些实现中,例如授权,我们希望在逻辑到达资源之前执行。ASP.NET 提供了两种在请求管道中注入逻辑的方式:HttpHandlers
和 HttpModules
。
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
并注册此模块应订阅的必要事件。例如,在此示例中,我们注册了 BeginRequest
和 EndRequest
事件。在这些事件中,我们只是将一个条目写入日志文件。
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
参考
如需进一步阅读,请观看以下面试准备视频和分步视频系列。