httpModules与Http模块
httpModules是往当前应用程序添加HttpModule(http模块)的标签。配置节如下
<httpModules> <add name="ModuleName" type=".NET Class, Assembly [,Version=version number] [,Culture=culture] [,PublicKeyToken=token]"/> <remove... /> <clear/> </httpModules>
提起httpModule不得不提一下Http请求处理流程
ASP.NET对请求处理的过程:
当请求一个*.aspx文件的时候,这个请求会被inetinfo.exe进程截获,它判断文件的后缀(aspx)之后,将这个请求转交给ASPNET_ISAPI.dll,ASPNET_ISAPI.dll会通过http管道(Http PipeLine)将请求发送给ASPNET_WP.exe进程,在ASPNET_WP.exe进程中通过HttpRuntime来处理这个请求,处理完毕将结果返回客户端。
Http 管道:
1. HttpRuntime将Http请求转交给 HttpApplication,HttpApplication代表着程序员创建的Web应用程序。HttpApplication创建针对此Http请求的 HttpContext对象,这些对象包含了关于此请求的诸多其他对象,主要是HttpRequest、HttpResponse、HttpSessionState等。这些对象在程序中可以通过Page类或者Context类进行访问。、
2. 接下来Http请求通过一系列Module,这些Module对Http请求具有完全的控制权。这些Module可以做一些执行某个实际工作前的事情。
3. Http请求经过所有的Module之后,它会被HttpHandler处理。在这一步,执行实际的一些操作,通常也就是.aspx页面所完成的业务逻辑。可能你会觉得在创建.aspx页面并没有体会到这一过程,但是,你一定知道,.aspx 页面继承自Page类,我们看一下Page类的签名:
public class Page : TemplateControl, IHttpHandler{ // 代码省略 }
可以看到,Page类实现了IHttpHandler接口,HttpHandler也是Http请求处理的最底层。
4.HttpHandler处理完以后,Http请求再一次回到Module,此时Module可以做一些某个工作已经完成了之后的事情。
从第二步到第四步可以用下面的图来展示
在http请求的处理过程中,只能调用一个HttpHandler,但可以调用多个HttpModule。
下面则详细说说HttpModule
HTTP 模块是一个在每次针对应用程序发出请求时调用的程序集。HTTP 模块作为请求管道的一部分调用,它们能够在整个请求过程中访问生命周期事件。因此,HTTP 模块使您可以检查传入的请求并根据该请求进行操作。它们还使您可以检查传出的响应并修改它。
ASP.NET HTTP 模块针对所有请求调用,这与 ISAPI 筛选器类似。但是它们是用托管代码编写的,而且可以与 ASP.NET 应用程序的生命周期完全集成。可以将自定义模块源代码放在应用程序的 App_Code 文件夹中,也可以将经过编译的自定义模块作为程序集放在应用程序的 Bin 文件夹中。
ASP.NET 使用模块来实现各个应用程序功能,其中包括 Forms 身份验证、缓存、会话状态和客户端脚本服务。在每种情况下,如果这些服务处于启用状态,模块会作为请求的一部分调用,并执行在任何单一页请求范围之外的任务。模块可以使用应用程序事件,可能会引发可在 Global.asax 文件中处理的事件。
功能:
模块可以订阅多种请求管道通知。模块可以接收 HttpApplication 对象的事件通知。
使用场景
HTTP 模块通常具有以下用途:
- 安全 因为您可以检查传入的请求,所以 HTTP 模块可以在调用请求页、XML Web services 或处理程序之前执行自定义的身份验证或其他安全检查。在以集成模式运行的 Internet 信息服务 (IIS) 7.0 中,可以将 Forms 身份验证扩展到应用程序中的所有内容类型。
- 统计信息和日志记录 因为 HTTP 模块是在每次请求时调用的,所以,您可以将请求统计信息和日志信息收集到一个集中的模块中,而不是收集到各页中。
- 自定义的页眉或页脚 因为您可以修改传出响应,所以可以在每一个页面或 XML Web services 响应中插入内容,如自定义的标头信息。
ASP.NET中一些内置的HttpModule
名称 |
类型 |
功能 |
OutputCache |
System.Web.Caching.OutputCacheModule |
页面级输出缓存 |
Session |
System.Web.SessionState.SessionStateModule |
Session状态管理 |
WindowsAuthentication |
System.Web.Security.WindowsAuthenticationModule |
用集成Windows身份验证进行客户端验证 |
FormsAuthentication |
System.Web.Security.FormsAuthenticationModule |
用基于Cookie的窗体身份验证进行客户端身份验证 |
PassportAuthentication |
System.Web.Security.PassportAuthenticationModule |
用MS护照进行客户身份验证 |
RoleManager |
System.Web.Security.RoleManagerModule |
管理当前用户角色 |
UrlAuthorization |
System.Web.Security.UrlAuthorizationModule |
判断用户是否被授权访问某一URL |
FileAuthorization |
System.Web.Security.FileAuthorizationModule |
判断用户是否被授权访问某一资源 |
AnonymousIdentification |
System.Web.Security.AnonymousIdentificationModule |
管理Asp.Net应用程序中的匿名访问 |
Profile |
System.Web.Profile.ProfileModule |
管理用户档案文件的创立及相关事件 |
ErrorHandlerModule |
System.Web.Mobile.ErrorHandlerModule |
捕捉异常,格式化错误提示字符,传递给客户端程序 |
下面摘抄了MSDN上的一个例子,自定义一个HttpModule
HttpModule必须实现接口System.Web.IHttpModule
namespace FastDoge.Study { public class MyModule : IHttpModule { public void Dispose() { } public void Init(HttpApplication context) { context.BeginRequest += (new EventHandler(this.Application_BeginRequest)); context.EndRequest += (new EventHandler(this.Application_EndRequest)); } private void Application_BeginRequest(Object source, EventArgs e) { HttpApplication application = (HttpApplication)source; HttpContext context = application.Context; context.Response.Write("<h1><font color=red>" + "HelloWorldModule: Beginning of Request" + "</font></h1><hr>"); } private void Application_EndRequest(Object source, EventArgs e) { HttpApplication application = (HttpApplication)source; HttpContext context = application.Context; context.Response.Write("<hr><h1><font color=red>" + "HelloWorldModule: End of Request</font></h1>"); } }
在 IIS 6.0 和 IIS 7.0 经典模式下运行的Web.config添加以下配置
<configuration> <system.web> <httpModules> <add name="myModule" type="FastDoge.Study.MyModule"/> </httpModules> </system.web> </configuration>
由于鄙人用的是IIS7集成模式,配置会不一样
<system.webServer> <modules> <add name="myModule" type="FastDoge.Study.MyModule"/> </modules> </system.webServer>
效果如下所示
当然网站不能是空网站,否则输出的只是一行
<hr><h1><font color=red>HelloWorldModule: End of Request</font></h1>
的字符串。在Init方法中传入的HttpApplication 对象可以绑定的事件可以参考ASP.NET 应用程序生命周期中提到的,事件一共20几个。
在网上找了一幅图,列出了事件触发的顺序
BeginRequest和PreRequestHandlerExecute之间的事件是在服务器执行HttpHandler处理之前触发。
PostRequestHandlerExecute和PreSendRequestContent之间的事件是在服务器执行Handler处理之后触发。
可是鄙人纠结的一点在于没发现某个ASP.NET内置的HttpModule调用了Handler。对于ASP.NET WebForm来说,每个Page都是一个Handler。而对ASP.NET MVC来说,在之前看蒋金楠老是的著作时看到的是触发一个UrlRoutingModule,它在OnPostResolveRequestCache事件中给HttpContext指定了一个MvcHandler。这样就会使得HttpHandler会被调用?或许需要看一下源码了。另外还有一个值得学习的地方就是这种模块的添加以及往Application注册事件的形式,使得HttpApplication具备的较好的灵活性。
在入行之初写过一篇博客,就用到HttpModule,当时有位园友评论说可以用Global.asax。结合当时的场景确实如此。但是两者对比起来肯定有弊有利。
模块相对于 Global.asax 文件具有如下优点:模块可以进行封装,因此可以在创建一次后在许多不同的应用程序中使用。
用 Global.asax 文件的好处在于可以处理其他已注册事件,如 Session_Start 和 Session_End。此外,Global.asax 文件还允许您实例化可在整个应用程序中使用的全局对象。
当您必须创建依赖应用程序事件的代码,并且符合以下条件时,都应该使用模块:
- 希望在其他应用程序中重用该模块。
- 希望避免将复杂代码放在 Global.asax 文件中。
- 该模块应用于管道中的所有请求(仅限 IIS 7.0 集成模式)。
当您必须创建依赖应用程序事件的代码并且不需要跨应用程序重用代码时,应该将代码添加到 Global.asax 文件中。