SAL

  博客园  :: 首页  :: 新随笔  :: 订阅 订阅  :: 管理

HttpModule的认识与深入理解

Posted on 2009-11-07 12:00  SAL  阅读(263)  评论(0编辑  收藏  举报

HttpModule是向实现类提供模块初始化和处置事件。当一个HTTP请求到达HttpModule时,整个ASP.NET Framework系统还并没有对这个HTTP请求做任何处理,也就是说此时对于HTTP请求来讲,HttpModule是一个HTTP请求的“必经之路”,所以可以在这个HTTP请求传递到真正的请求处理中心(HttpHandler)之前附加一些需要的信息在这个HTTP请求信息之上,或者针对截获的这个HTTP请求信息作一些额外的工作,或者在某些情况下干脆终止满足一些条件的HTTP请求,从而可以起到一个Filter过滤器的作用。


首先你要实现IHttpModule接口这个接口只有两个方法,一个是Init方法一个Dispose方法.


using System;

namespace
 System.Web
{
    
//
 Summary:
    
//     Provides module initialization and disposal events to the implementing class.

    public interface IHttpModule
    {
        
//
 Summary:
        
//
     Disposes of the resources (other than memory) used by the module that implements
        
//     System.Web.IHttpModule.

        void Dispose();
        
//

        
// Summary:
        
//
     Initializes a module and prepares it to handle requests.
        
//

        
// Parameters:
        
//
   context:
        
//
     An System.Web.HttpApplication that provides access to the methods, properties,
        
//     and events common to all application objects within an ASP.NET application

        void Init(HttpApplication context);
    }
}

 

一个HTTP请求在HttpModule容器的传递过程中,会在某一时刻(ResolveRequestCache事件)将这个HTTP请求传递给HttpHandler容器。在这个事件之后,HttpModule容器会建立一个HttpHandler的入口实例,但是此时并没有将HTTP请求控制权交出,而是继续触发AcquireRequestState事件以及PreRequestHandlerExcute事件。在PreRequestHandlerExcute事件之后,HttpModule窗口就会将控制权暂时交给HttpHandler容器,以便进行真正的HTTP请求处理工作。


而在HttpHandler容器内部会执行ProcessRequest方法来处理HTTP请求。在容器HttpHandler处理完毕整个HTTP请求之后,会将控制权交还给HttpModule,HttpModule则会继续对处理完毕的HTTP请求信息流进行层层的转交动作,直到返回到客户端为止。


HttpModule过程在下面的事件:
BeginRequest    指示请求处理开始。
AuthenticateRequest PostAuthenticateRequest    封装请求身份验证过程。
AuthorizeRequest   PostAuthorizeRequest    封装请求授权过程。 
ResolveRequestCache PostResolveRequestCache    封装检查是否能利用以前缓存的输出页面处理请求的过程。
PostMapRequestHandler    指示已发现用于处理请求的 HTTP 处理程序。
AcquireRequestState    PostAcquireRequestState    封装对请求会话状态的检索。
PostRequestHandlerExecute    指示用于处理请求的 HTTP 处理程序已执行。
ReleaseRequestState   PostReleaseRequestState    封装对请求会话状态的发布。
UpdateRequestCache    PostUpdateRequestCache    封装检查是否应对请求的资源的输出进行缓存以备今后重复使用的过程。
EndRequest    指示请求处理结束。

 

可以利用HttpModule通过调用HttpApplication.CompleteRequest()方法实现当满足某一个条件时终止此次的HTTP请求。需要注意的是,即使调用了HttpApplication.CompleteRequest()方法终止了一个HTTP请求,ASP.NET Framework仍然会触发HttpApplication后面的这3个事件:EndRequest事件、PreSendRequestHeaders事件、PreSendRequestContent事件。
如果存在多个自定义的HttpModule的话,当Module1终止了一个HTTP请求,这个HTTP请求将不会再触发Module2中相应的事件了,但Module2的最后三个事件仍会被触发。


public class CompleteRequestHttpModule : IHttpModule
    {
        
#region IHttpModule 成员

         
public void Dispose()
        {} 

        
public void
 Init(HttpApplication application)
        {
            application.BeginRequest 
+= new
 EventHandler(Application_BeginRequest);
        } 

        
void Application_BeginRequest(object
 sender, EventArgs e)
        {
            HttpApplication application 
=
 (HttpApplication)sender;
            application.CompleteRequest();
            application.Context.Response.Write(
"请求被终止。"
);
        } 
        
#endregion

    }


HttpModule示例:

 过滤http请求


    /// <summary>
    
/// 页面访问验证模块
    
/// </summary>

    public class AuthenticationModule : IHttpModule
    {
        
#region IHttpModule Members


        
public void Dispose()
        {
        }

        
public void
 Init(HttpApplication context)
        {
            context.AcquireRequestState 
+= new
 EventHandler(context_AcquireRequestState);
        }

        
#endregion


        
private void context_AcquireRequestState(object sender, EventArgs e)
        {
            HttpContext context 
=
 HttpContext.Current;
            
string path =
 context.Request.Path.ToLower();
            
// 只处理aspx文件,因为其他文件无法获得Session对象,无法判断是否已经登录

            if (path.EndsWith(".aspx"))
            {
                
// 如果用户没有登录就會返回false

                if (!UserRules.Instance.IsCurrentUserLogined)
                {
                    
// 对于公共文件夹和根目录的文件不做判断

                    if (path.StartsWith("/" + AppSettings.PUBLICFOLDERNAME + "/")==false && !(path.LastIndexOf("/"== 0))
                    {
                        
// 跳转到公共页面首页                        

                        context.Response.Redirect(AppSettings.PUBLICLOGOUTFILENAME, false);
                        context.ApplicationInstance.CompleteRequest();
                    }
                }
            }
        }
    }

在web.confg中添加httpModules节点注册事件
<httpModules>
     <add name="AuthenticationModule" type="Business.AuthenticationModule, Business"/>
</httpModules>

 
判断浏览器的版本 


using System;
using
 System.Data;
using
 System.Configuration;
using
 System.Web;
using
 System.Web.Security;
using
 System.Web.UI;
using
 System.Web.UI.WebControls;
using
 System.Web.UI.WebControls.WebParts;
using
 System.Web.UI.HtmlControls;

/// <summary>

/// BrowserModule 的摘要说明
/// </summary>

public class BrowserModule : IHttpModule
{
    
public
 BrowserModule()
    {
        
//

        
// TODO: 在此处添加构造函数逻辑
        
//
    }

    
#region IHttpModule 成员


    
public void Dispose()
    {

    }

    
public void
 Init(HttpApplication context)
    {
        
//添加判断事件

        context.BeginRequest += new EventHandler(context_BeginRequest);
        context.EndRequest 
+= new
 EventHandler(context_EndRequest);
    }

    
void context_EndRequest(object
 sender, EventArgs e)
    {
        
if
 (isfalse)
        {
            HttpApplication application 
=
 (HttpApplication)sender;
            application.Context.Response.Clear();
//清空浏览器所有的内容

            application.Context.Response.Output.Write("浏览器不符合要求");
        }

    }
    
public bool isfalse = false;//判断浏览器是否符合要求

    void context_BeginRequest(object sender, EventArgs e)
    {
        HttpApplication application 
= (HttpApplication)sender;//获得实际发生事件的对象

        HttpBrowserCapabilities browser = application.Context.Request.Browser;//获得浏览器的相关信息
        
//
获得浏览器的名字  application.Context.Response.Output.Write(browser.Browser);
        
//获得浏览器的版本号 application.Context.Response.Output.Write(browser.MajorVersion );

        if (browser.Browser != "IE" || browser.MajorVersion < 7)//判断浏览器的版本是否是IE5以上的
        {
            
string strBrowserChooserPage = "";//创建变量装载浏览器不符合条件后要导入的页面

            try
            {
                strBrowserChooserPage 
= ConfigurationManager.AppSettings["BrowserChooserPage"];//从配置文件中导入要浏览的页面
            }
            
catch
 (System.Configuration.ConfigurationErrorsException ex)
            {
                
throw new Exception(string.Format("请正确配置web.config AppSetting[BrowserChooserPage]节点,系统错误提示:{0}"
, ex.Message));
            }
            
catch
 (System.Exception ex)
            {
                
throw
 ex;
            }
            isfalse 
= true;//为True的时候浏览器不符合要求,处理完context_BeginRequest事件后,最好在处理context_EndRequest事件的时候判断是否合适

        }
        
else

        {
         
            application.Context.Response.Output.Write(
"浏览器符合要求");
        }
    }
    
#endregion

}

注册web.config事件

实现URL重写


using System;
using
 System.Data;
using
 System.Configuration;
using
 System.Web;
using
 System.Web.Security;
using
 System.Web.UI;
using
 System.Web.UI.WebControls;
using
 System.Web.UI.WebControls.WebParts;
using
 System.Web.UI.HtmlControls;

/// <summary>

/// UrlReWriteHttpModule 的摘要说明
/// </summary>

public class UrlReWriteHttpModule : IHttpModule
{
    
public
 UrlReWriteHttpModule()
    {
        
//

        
// TODO: 在此处添加构造函数逻辑
        
//
    }

    
#region IHttpModule 成员


    
public void Dispose()
    {
        
throw new Exception("The method or operation is not implemented."
);
    }

    
public void
 Init(HttpApplication context)
    {
        context.BeginRequest 
+= new
 EventHandler(context_BeginRequest);
    }

    
void context_BeginRequest(object
 sender, EventArgs e)
    {
        HttpContext context 
= (sender as
 HttpApplication).Context;
        
//
string Url1 = context.Request.Path;
        
//
string Url2 = context.Request.PathInfo;
        
//
string Url3 = context.Request.Url.ToString();
        
//得到整个的网络地址

        string fullOrigionalpath = context.Request .Url.ToString();

        
if (fullOrigionalpath.Contains("/Books.aspx"
))
        {
            context.RewritePath(
"Products.aspx?Category=Books");//重写地址,重写后地址栏中的显示不变,但是真正返回的页面是被重写的页面

        }
        
else if (fullOrigionalpath.Contains("/DVDs.aspx"
))
        {
            context.RewritePath(
"Products.aspx?Category=DVDs"
);
        }
        
else if (fullOrigionalpath.Contains("/DVDs.aspx"
))
        {
            context.RewritePath(
"Products.aspx?Category=CDs.aspx"
);
        }
    }

    
#endregion

}

 注册web.config事件

-------------------------------------------------完成------------------------------------------------

从上面的例子看出,其实是一个好简单的实现方法,就是在init中注册处理过程事件,把代码写完后,在web.congif中HttpModules注册就完成了.

开发程序千变万变, 通过这一方法可以编写出好多合适自己用的功能,这需要大家去实践了. 收集与整理,且当成长的回忆.