.Net使用HttpModule过滤请求
编写自己的HttpModule
要实现HttpModule,必须实现接口IHttpModule。
using System; namespace System.Web { public interface IHttpModule { // 销毁不再被HttpModule使用的资源 void Dispose(); // 初始化一个Module,为捕获HttpRequest做准备 void Init(HttpApplication context); } }
下面是自己的HttpModule
/// <summary> /// 需要在网站的 Web.config 文件中配置此模块,向 IIS 注册它,然后才能使用它。 /// </summary> public class MyHttpModule : IHttpModule { public void Init(HttpApplication context) { context.PreRequestHandlerExecute += new EventHandler(Application_PreRequestHandlerExecute); context.BeginRequest += new EventHandler(Application_BeginRequest); context.EndRequest += new EventHandler(Application_EndRequest); } public void Application_PreRequestHandlerExecute(object sender, EventArgs e) { HttpApplication application = sender as HttpApplication; string url = application.Request.RawUrl; if (url.Contains("HttpModule_HtmlTest")) { application.Response.Redirect("~/HttpModule_Index.html"); application.Response.End(); } else if (url.Contains("HttpModule_JsonTest")) { dynamic obj = new System.Dynamic.ExpandoObject(); obj = new { res = 0, msg = "请求被拦截!", }; string jsonRes = Newtonsoft.Json.JsonConvert.SerializeObject(obj); application.Response.Write(jsonRes); application.Response.ContentType = "text/html;charset=UTF-8"; application.Response.End(); } } public void Application_BeginRequest(object sender, EventArgs e) { HttpApplication application = sender as HttpApplication; HttpContext context = application.Context; HttpResponse response = context.Response; response.Write("这是来自自定义HttpModule中有BeginRequest"); } public void Application_EndRequest(object sender, EventArgs e) { HttpApplication application = sender as HttpApplication; HttpContext context = application.Context; HttpResponse response = context.Response; response.Write("这是来自自定义HttpModule中有EndRequest"); } public void Dispose() { } }
web.config
1 <!--自定义过滤器IIS6(对IIS7的经典模式起作用) --> 2 <system.web> 3 <httpModules> 4 <add name="myHttpModule" type="namespace.MyHttpModule, namespace" /> 5 </httpModules> 6 </system.web> 7 <system.webServer> 8 <!-- 在IIS7的集成模式下,加上了preCondition="managedHandler"这个配置项后,就不会去处理静态文件(.html .css .js .jpeg等)的请求了,只会处理托管文件(aspx, ascx 及 MVC等)的请求 9 <add name="webServerHttpModule" type="namespace.MyHttpModule, namespace" preCondition="managedHandler" /> 10 --> 11 <modules> 12 <add name="webServerHttpModule" type="namespace.MyHttpModule, namespace" /> 13 </modules> 14 </system.webServer>
default.aspx.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.UI; 6 using System.Web.UI.WebControls; 7 public partial class _Default : System.Web.UI.Page 8 { 9 protected void Page_Load(object sender, EventArgs e) 10 { 11 Response.Write("<br/><br/>来自Default.aspx页面<br/>"); 12 } 13 }
效果图
HttpModule内部事件机制和生命周期
HttpModule对HttpApplication实例进行处理,而HttpApplication有很多事件(对应不同的生命期),这样就衍生出HttpModule内部事件机制和生命周期。
(1)、可以重写的事件有
// 摘要: // 当 ASP.NET 获取与当前请求关联的当前状态(如会话状态)时发生。 public event EventHandler AcquireRequestState; // // 摘要: // 当安全模块已建立用户标识时发生。 public event EventHandler AuthenticateRequest; // // 摘要: // 当安全模块已验证用户授权时发生。 public event EventHandler AuthorizeRequest; // // 摘要: // 在 ASP.NET 响应请求时作为 HTTP 执行管线链中的第一个事件发生。 public event EventHandler BeginRequest; // // 摘要: // 在释放应用程序时发生。 public event EventHandler Disposed; // // 摘要: // 在 ASP.NET 响应请求时作为 HTTP 执行管线链中的最后一个事件发生。 public event EventHandler EndRequest; // // 摘要: // 当引发未经处理的异常时发生。 public event EventHandler Error; // // 摘要: // 恰好在 ASP.NET 为当前请求执行任何记录之前发生。 public event EventHandler LogRequest; // // 摘要: // 在选择了用来响应请求的处理程序时发生。 public event EventHandler MapRequestHandler; // // 摘要: // 在已获得与当前请求关联的请求状态(例如会话状态)时发生。 public event EventHandler PostAcquireRequestState; // // 摘要: // 当安全模块已建立用户标识时发生。 public event EventHandler PostAuthenticateRequest; // // 摘要: // 在当前请求的用户已获授权时发生。 public event EventHandler PostAuthorizeRequest; // // 摘要: // 在 ASP.NET 处理完 System.Web.HttpApplication.LogRequest 事件的所有事件处理程序后发生。 public event EventHandler PostLogRequest; // // 摘要: // 在 ASP.NET 已将当前请求映射到相应的事件处理程序时发生。 public event EventHandler PostMapRequestHandler; // // 摘要: // 在 ASP.NET 已完成所有请求事件处理程序的执行并且请求状态数据已存储时发生。 public event EventHandler PostReleaseRequestState; // // 摘要: // 在 ASP.NET 事件处理程序(例如,某页或某个 XML Web service)执行完毕时发生。 public event EventHandler PostRequestHandlerExecute; // // 摘要: // 在 ASP.NET 跳过当前事件处理程序的执行并允许缓存模块满足来自缓存的请求时发生。 public event EventHandler PostResolveRequestCache; // // 摘要: // 在 ASP.NET 完成缓存模块的更新并存储了用于从缓存中为后续请求提供服务的响应后,发生此事件。 public event EventHandler PostUpdateRequestCache; // // 摘要: // 恰好在 ASP.NET 开始执行事件处理程序(例如,某页或某个 XML Web services)前发生。 public event EventHandler PreRequestHandlerExecute; // // 摘要: // 恰好在 ASP.NET 向客户端发送内容之前发生。 public event EventHandler PreSendRequestContent; // // 摘要: // 恰好在 ASP.NET 向客户端发送 HTTP 标头之前发生。 public event EventHandler PreSendRequestHeaders; // // 摘要: // 在 ASP.NET 执行完所有请求事件处理程序后发生。该事件将使状态模块保存当前状态数据。 public event EventHandler ReleaseRequestState; // // 摘要: // 在 ASP.NET 完成授权事件以使缓存模块从缓存中为请求提供服务后发生,从而绕过事件处理程序(例如某个页或 XML Web services)的执行。 public event EventHandler ResolveRequestCache; // // 摘要: // 当 ASP.NET 执行完事件处理程序以使缓存模块存储将用于从缓存为后续请求提供服务的响应时发生。 public event EventHandler UpdateRequestCache;
(2)、验证HttpModule生命周期
说明:
a、HttpModule容器会将HttpRequest传递到HttpHandler容器,这个时间点是ResolveRequestCache事件
b、HttpModule容器会建立HttpHandler实例作为入口——Session从此生效
c、触发AcquireRequestState事件以及PreRequestHandlerExecute事件
d、HttpModule容器便将对HttpRequest的控制权转让给HttpHandler容器
e、HttpHandler容器处理HttpRequest——使用自身的ProcessRequest方法,将对其控制权又还给HttpModule容器——之后Session失效。
验证生命周期代码:
public class ValidaterHttpModuleEvents : IHttpModule { /// <summary> /// 验证HttpModule事件机制 /// </summary> /// <param name="application"></param> public void Init(HttpApplication application) { application.BeginRequest += new EventHandler(application_BeginRequest); application.EndRequest += new EventHandler(application_EndRequest); application.AcquireRequestState += new EventHandler(application_AcquireRequestState); application.AuthenticateRequest += new EventHandler(application_AuthenticateRequest); application.AuthorizeRequest += new EventHandler(application_AuthorizeRequest); application.PreRequestHandlerExecute += new EventHandler(application_PreRequestHandlerExecute); application.PostRequestHandlerExecute += new EventHandler(application_PostRequestHandlerExecute); application.ReleaseRequestState += new EventHandler(application_ReleaseRequestState); application.ResolveRequestCache += new EventHandler(application_ResolveRequestCache); application.PreSendRequestHeaders += new EventHandler(application_PreSendRequestHeaders); application.PreSendRequestContent += new EventHandler(application_PreSendRequestContent); } private void application_BeginRequest(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; application.Context.Response.Write("application_BeginRequest<br/>"); } private void application_EndRequest(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; application.Context.Response.Write("application_EndRequest<br/>"); } private void application_PreRequestHandlerExecute(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; application.Context.Response.Write("application_PreRequestHandlerExecute<br/>"); } private void application_PostRequestHandlerExecute(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; application.Context.Response.Write("application_PostRequestHandlerExecute<br/>"); } private void application_ReleaseRequestState(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; application.Context.Response.Write("application_ReleaseRequestState<br/>"); } private void application_AcquireRequestState(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; application.Context.Response.Write("application_AcquireRequestState<br/>"); } private void application_PreSendRequestContent(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; application.Context.Response.Write("application_PreSendRequestContent<br/>"); } private void application_PreSendRequestHeaders(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; application.Context.Response.Write("application_PreSendRequestHeaders<br/>"); } private void application_ResolveRequestCache(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; application.Context.Response.Write("application_ResolveRequestCache<br/>"); } private void application_AuthorizeRequest(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; application.Context.Response.Write("application_AuthorizeRequest<br/>"); } private void application_AuthenticateRequest(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; application.Context.Response.Write("application_AuthenticateRequest<br/>"); } public void Dispose() { } }
HttpModule1和HttpModule2模仿ValidaterHttpModuleEvents编写(除了类名改变外,事件和方法不变)
<system.web> <httpModules> <add name="Module1" type="namespace.HttpModule1, namespace" /> <add name="Module2" type="namespace.HttpModule2, namespace" /> </httpModules> </system.web>
运行结果如下
说明:
a、对于一个HttpModule,在BeginRquest中终止,但是仍然会调用EndRequest事件,以及PreSendRequestHeaders事件和PreSendRequestContent事件。也可以说是直接跳转到EndRequest事件,而不会调用这期间的事件
b、如果有两个HttpModule,在第一个HttpModule的BeginRequest中终止,仅仅不会调用第二个HttpModule的BeginRequest,但仍然会调用两个EndRequest事件,以及PreSendRequestHeaders事件和PreSendRequestContent事件。看下面的图示:
扩展性
- 实现自定义HttpModule拦截异常处理
- 强制站点范围的Cookie策略
- 集中化监控与日志
- 编写设置与删除HTTP头
- 控制response输出,如删除多余空白字符
- Session管理
- 认证与受权
- 自定义IP请求限制
其他
轻松实现ajax跨域访问
1.使用jsonp(只支持get方式)
2.在header添加以下信息(支持所有方式,也可以在IIS的HTTP响应标头统一设置)
Access-Control-Allow-Methods:POST, GET, OPTIONS, DELETE
Access-Control-Allow-Origin:*
Access-Control-Max-Age:3600