这篇着重讲一下Asp.Net在从Browser发出请求一直到服务器返回数据这中间竟然发生了一些什么事,作为一个.Net(B/S)开发人员,我们应当对此进行了解,所谓要知其然,也要知其所以然.

 

下面分步骤说先说下Asp.Net请求处理的流程.

1、当客户端发出一个HTTP请求到服务器并被IIS接收到之后,IIS首先通过客户端请求的页面类型为其加载相应的.dll文件,如果是Asp.Net那就是aspnet_isapi.dll(IIS中注册ASP.NET的ISAPI扩展),

这就使得作为ASP.NET宿主的IIS在接收到客户端的HTTP请求后,将响应请求的控制权交给ASP.NET运行。

2、IIS判断文件后缀之后,把这个请求转交给aspnet_isapi.dll,而aspnet_isapi.dll则会通过一个Http PipeLine的管道,将这个http请求发送给aspnet_wp.exe进程,

当这个HTTP请求进入aspnet_wp.exe进程之后,asp.net framework就会通过HttpRuntime(ProcessRequest)来处理这个Http请求.

3、HttpRuntime将Http请求转交给 HttpApplication,HttpApplication代表着程序员创建的Web应用程序。如果应用程序具有 Global.asax 文件,则ASP.NET会创建Global.asax 类(从HttpApplication类派生)

的一个实例,并使用该派生类表示应用程序。

4、接下来Http请求通过一系列Module,这些Module对Http请求具有完全的控制权。

5、Http请求经过所有的Module之后,它会被HttpHandler处理,这是Http请求的最底层,在这一步,执行实际的一些操作,通常也就是.aspx页面所完成的业务逻辑。可能你会觉得在创建.aspx页面并没有体会到这一过程,但你一定知道,aspx 页面继承自Page类,而Page类是继承IHttpHandler接口.

下面的图例可以很好的诠释Http请求的处理流程:

114921958

下面要着重说一下HttpModule这个东西.

每次http请求都会有一个HttpApplication类型的对象来管理这次请求的过程,为每次http请求创建一个HttpContext对象,此对象在整个Http处理过程中都是可访问的。

HttpContext对象经过不同部分时,HttpApplication对象会先后激发出一连串的事件,而这些事件可以由HTTP模块(HTTP Module)来响应,HTTP模块对象是在HttpApplication对象的InitModules()方法中被创建的,创建时会调用其init方法,我们一般在HTTP模块对象Init()方法中书写代码对HttpApplication对象的事件进行注册。

我们通过Http Module中注册期望对应用程序事件做出反应的方法,在相应的事件触发的时候(比如说BeginRequest 事件,它在应用程序收到一个Http请求并即将对其进行处理时触发),便会调用Http Module注册了的方法,实际的工作在这些方法中执行,下面的图例说明了Http Request请求的生命周期,Http Module各事件的执行顺序等。

0PS5BC-2

在上图中我们看到,其实在在Http请求由IHttpHandler处理之前,它需要通过一系列的Http Module,在请求处理之后,它需要再次通过一系列的Http Module,然后将处理后的数据返回给客户端,

而Http Module的作用是与应用程序事件密切相关的。

在Asp.Net中本身已经有了各种Http Module,下面列出了C:\WINDOWS\Microsoft.NET\Framework\ v2.0.50727\CONFIG下的Web.Config中的 Asp.Net 内置的Http Modules 及其主要作用。

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
捕捉异常,格式化错误提示字符,传递给客户端程序

<httpModules> 
    <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" /> 
    <add name="Session" type="System.Web.SessionState.SessionStateModule" /> 
    <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" /> 
    <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" /> 
    <add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule" /> 
    <add name="RoleManager" type="System.Web.Security.RoleManagerModule" /> 
    <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" /> 
</httpModules>

下面我们自己去继承IHttpModule,实现一个自定义的Http Module.

/// <summary> 
/// 要在HttpModule中获取相关session,那么就需要注意整个流程,在上面的流程图中有明确的说明,AcquireRequestState执行 
/// 这一阶段才能开始获取session,于是将有关的function挂到AcquireRequestState中就可以获得session了。 
/// </summary>
public class HttpModule : System.Web.IHttpModule
{
    /// <summary> 
   /// 实现接口的Init方法 
    /// </summary> 
   /// <param name="context"></param> 
   public void Init(HttpApplication context) 
    { 
        context.BeginRequest += new EventHandler(KillSqlFilter); 
        ontext.AcquireRequestState += new EventHandler(Authority); //验证权限 
     }

    /// <summary> 
    /// 权限系统初始化,基于路径的指定权限,判断基于后缀名为.aspx的,不要每件事都判断 
    /// </summary> 
    /// <param name="sender"></param> 
    /// <param name="e"></param> 
    private void Authority(object sender, EventArgs e) 
     {
         HttpContext context = ((HttpApplication)sender).Context;

         string requestPath = context.Request.Path.ToLower().Trim(); //获得当前页面,包含目录 
          string requestPage = requestPath.Substring(requestPath.LastIndexOf("/")); //获得当前页面,不包含目录

          if (requestPath.Substring(requestPath.LastIndexOf(".")) == ".aspx" || requestPath.Substring(requestPath.LastIndexOf(".")) == "ashx") 
          {
             rights_config rconfig = new rights_config();
             if (rconfig.is_on_the_scope(requestPath)) {   //定义一个xml文件,将需要判断权限的页面全部放入这个xml文件中,然后遍历这个xml,如果当前的requestPath在这个xml中,则通过
                 if (context.Session["UserGroup"] == null || string.IsNullOrEmpty(context.Session["UserGroup"].ToString())==true) { //定义格式如<unit path="/smart_voter/vote_add.aspx" /> 
                 context.Session["error_msg"] = "请先登录后台系统,不允许非法进入页面访问!"; 
                    context.Response.Redirect("../error_msg.aspx"); 
                    context.Response.End(); 
                 }
                 else { 
                   //先处理相关的数组 
                   string all_group = context.Session["UserGroup"].ToString(); 
                   string[] str_groups = all_group.Trim().Split(',');

                   bool hasRight = CheckAuthority(str_groups, requestPath); //验证权限的方法,具体业务逻辑不再去详细写了 
                   if (hasRight == true) { } 
                   else {
                      context.Session["error_msg"] = "很抱歉,您没有访问这个页面的权限!"; 
                      context.Response.Redirect("../error_msg.aspx"); 
                   context.Response.End(); 
                }
             }
          }
       }
    }
}
自定义的HttpModule类需要同样在web.config中进行注册
<system.web>
    <httpModules> 
       <add name="HttpModule" type="MyModule.Web.UI.HttpModule,MyModule.Web.UI" /> 
    </httpModules>
</system.web>

在客户请求某个Web页面的时候(这个Web页面通常同某个业务功能相关联),可以通过自定义HttpModule的方法判断这个用户是否具备对请求资源的访问权限。

如果有,那么,过滤器可以把这个请求放过去什么都不做;否则,过滤器可以重定向到某个页面,告诉用户不能访问的原因,或者,直接抛出异常,交由前面的处理者处理。

通过这种方式,我们可以同样的分离诸如身份验证这样的系统功能和业务逻辑,实现更好的系统结构。

通过象Web服务器这样的应用程序环境提供的功能,我们实现类似AOP的这种拦截功能,构建更好的系统框架。

 

另外如果你想遍历Http Module的集合,可以使用下面的方法.

private string ShowModules() { 
   HttpApplication app = Context.ApplicationInstance; //获取当前上下文的HttpApplication环境 
    HttpModuleCollection moduleCollection = app.Modules; //获取所有Module集合 
    // 获取所有的 Module 名称 
    string[] moduleNames = moduleCollection.AllKeys; 
    System.Text.StringBuilder results = new System.Text.StringBuilder();    

    foreach (string name in moduleNames) {   //遍历结果集 
       // 获得Module名称 
       results.Append("<b style='color:#800800'>名称:" + name + "</b><br />"); 
        // 获得Module类型 
       results.Append("类型:" + moduleCollection[name].ToString() + "<br />"); 
    } 
    return results.ToString(); 
}

这篇主要内容就写到这,后面我会接着写关于IHttpHandler的内容.

 

posted on 2013-09-18 14:16  tzj19810812  阅读(412)  评论(0编辑  收藏  举报