在 ASP.NET 中实现 HTTPHandler 和 HTTPModule






4.75/5 (65投票s)
本文旨在了解 HTTPHandler 和 HTTPModule 在 ASP.NET 应用程序中的作用。
引言
本文旨在了解 HTTPHandler
和 HTTPModule
在 ASP.NET 应用程序中的作用。我们将尝试通过一个基本示例来了解如何实现它们。
背景
ASP.NET 处理来自用户的所有 HTTP
请求并生成相应的响应。ASP.NET 框架知道如何根据扩展名处理不同类型的请求,例如,它可以处理对 .aspx、.ascx 和 .txt 文件等的请求。当它收到任何请求时,它会检查扩展名以查看它是否可以处理该请求,并执行一些预定义的步骤来处理该请求。
现在,作为开发人员,我们可能希望插入自己的某些功能。我们可能希望处理一些新的请求类型,或者我们可能想自己处理现有请求以更好地控制生成的响应,例如,我们可能想决定如何处理对 .jpg 或 .gif 文件的请求。在这里,我们需要一个 HTTPHandler
来实现我们的功能。
有时,虽然我们对 ASP.NET 处理请求的方式感到满意,但我们希望在每个请求上执行一些附加任务,也就是说,我们希望我们的任务与 ASP.NET 在每个请求上执行的预定义步骤一起执行。如果我们要这样做,我们可以使用 HTTPModule
来实现。
因此,从上面的讨论可以清楚地看出,HTTPHandlers
被 ASP.NET 用于根据扩展名处理特定请求。另一方面,如果我们要将自己的功能与默认的 ASP.NET 功能一起使用,则使用 HTTPModule
。一个特定请求只有一个 Handler,但可以有很多模块。

Using the Code
让我们通过为每个概念编写一个小应用程序来尝试理解这两个概念。我们将尝试实现一个机制,通过该机制我们可以处理扩展名为 .bspx 和 .cspx 的网页。虽然这是一个非常不切实际的场景,但类似的理念用于创建对搜索引擎友好的 URL,所以也许它也不是那么不切实际。
注意:此处 HTTPHandler
示例仅用于演示目的,我不推荐将 HTTPHandlers
用于我即将要做的事情。HTTPHandlers
理想情况下应用于自定义现有 MIME 类型的处理,而不是用于提供对搜索引擎友好的 URL 或非标准 URL。
实现 HTTPHandler
根据我们的问题定义,让我们尝试看看如何使用 HTTPHandlers
来处理对 .cspx 页面的请求。首先,我们需要有 handler 类,所以让我们创建 handler 类。
public class CspxHandler :IHttpHandler
{
public bool IsReusable
{
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
}
}
该类应有一个名为 ProcessRequest
的方法和一个名为 IsReusable
的属性。该属性告诉该 handler 是否可以重用,当请求到来时会调用该方法。但是,我们是在哪里定义 handler 应该被调用的请求类型的?这可以在 IIS 中定义,如果我们有一个对服务器上运行的所有站点都通用的 handler,或者我们可以将其配置在 web.config 文件中,如果 handler 是特定于某个网站的。现在我们将其配置在 web.config 文件中。
<httpHandlers>
<add verb="*" path="*.cspx" type="CspxHandler"/>
</httpHandlers>
在这里,我们注册了我们的 handler,以指定如果收到对 .cspx 文件的任何请求,它都应转发到我们的 handler。
现在,由于我们没有任何“真实”的 .cspx 扩展名的文件,我们将要做的是处理对 .cspx 的请求,然后将用户重定向到相应的 .aspx 文件。
public class CspxHandler :IHttpHandler
{
public bool IsReusable
{
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
if (context.Request.RawUrl.Contains(".cspx"))
{
string newUrl = context.Request.RawUrl.Replace(".cspx", ".aspx");
context.Server.Transfer(newUrl);
}
}
}
每当收到对 .cspx 文件的请求时,我们都会在 handler 中处理它,而是显示相应的 .aspx 文件。让我们看看它是如何工作的。
注意:我还将启动页名称更改为 Default.cspx,但实际上没有名为 Default.cspx 的页面。我希望我的 handler 来处理它并向我显示实际的默认页面。

重要提示:我重申,此示例仅用于说明。这根本不是 HTTPHandlers
应该使用的方式。HTTPHandlers
理想情况下应用于自定义现有 MIME 类型的处理。
好吧,页面似乎工作正常,用户将看到他请求的 .cspx URL。但有一个问题。我们编写 handler 处理 postback
的方式不好。如果我在这些页面中的任何一个页面上添加一个按钮并进行 postback,原始 URL 就会显示出来。所以它不是解决问题的最佳方案,但它确实演示了 Handler 的使用方式。
实现 HTTPModule
我们如何解决刚才看到的那个问题?好吧,我们的应用程序需要 URL 重写,而 HTTPHandlers
是一个糟糕的解决方案,并且永远不应该用于此目的。所以也许使用这种技术创建对搜索引擎友好的 URL 的人应该重新考虑他们的策略。那么我们如何真正解决这个问题呢?
让我们再次看看需求,我们只需要向用户显示与实际 URL 不同的 URL,并在内部处理实际 URL。所以我们不需要自定义 handlers,我们对 ASP.NET 引擎处理这些请求的方式感到满意,但我们需要在处理阶段执行自定义活动。所以看起来我们可以使用 HTTPModule
来解决。
因此,让我们继续编写一个 HttpModule
,它将执行以下操作:
- 在请求时检查文件扩展名。
- 如果找到 .bspx 扩展名,则将其更改为 .aspx(或查找实际 URL,如果我们正在实现对搜索引擎友好的 URL)。
- 它会将请求传递给默认 handler,因为页面仍然是 aspx。
- 响应生成后,它会将原始 .bspx URL 写回用户的浏览器。
public class MyBModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
context.EndRequest += new EventHandler(context_EndRequest);
context.AuthorizeRequest += new EventHandler(context_AuthorizeRequest);
}
void context_AuthorizeRequest(object sender, EventArgs e)
{
//We change uri for invoking correct handler
HttpContext context = ((HttpApplication)sender).Context;
if (context.Request.RawUrl.Contains(".bspx"))
{
string url = context.Request.RawUrl.Replace(".bspx", ".aspx");
context.RewritePath(url);
}
}
void context_PreRequestHandlerExecute(object sender, EventArgs e)
{
//We set back the original url on browser
HttpContext context = ((HttpApplication)sender).Context;
if (context.Items["originalUrl"] != null)
{
context.RewritePath((string)context.Items["originalUrl"]);
}
}
void context_EndRequest(object sender, EventArgs e)
{
//We processed the request
}
void context_BeginRequest(object sender, EventArgs e)
{
//We received a request, so we save the original URL here
HttpContext context = ((HttpApplication)sender).Context;
if (context.Request.RawUrl.Contains(".bspx"))
{
context.Items["originalUrl"] = context.Request.RawUrl;
}
}
}
我们还需要注册我们的模块,以便可以调用它,我们将在 web.config 文件中这样做。
<httpModules>
<add name="MyBModule" type="MyBModule" />
</httpModules>
现在让我们运行应用程序。

这样,我们就解决了 postback 时 URL 恢复到原始 URL 的问题。这也是执行此操作的理想方式。
关注点
在本文中,我们学习了如何实现一个基本的 HTTPHandler
和 HTTPModule
。我们了解了它们在页面处理框架中的各自作用。我们通过一个示例解决了 URL 重写问题,先是错误地使用 HTTPHandler
(但我们了解了如何编写 HTTPhandler
),然后是正确地使用 HTTPModule
进行 URL 重写(我们也理解了这一点)。
本文的重点仅在于理解我们如何实现 HTTPHandlers
和 HTTPModules
的工作。示例有点不切实际,甚至可能有点误导,但既然我已经清楚地说明了这一点,应该就不会有问题。
在结束之前,关于 handlers 还有最后一件事我们应该知道。处理请求也可以是异步的。ASP.NET 提供了一种创建异步 handler 的机制,从而提高了网页的性能(通过实现 IHttpAsyncHandler
来实现)。
历史
- 2012 年 2 月 25 日:在 ASP.NET 中实现
HTTPHandlers
和HTTPModules