ASP.NET中Http请求处理流程

ASP.NET中Http请求处理流程

 

 

       目  录

1                     .概述.... 2

1.1       背景... 2

1.2       目的... 2

2                     .Http请求处理流程.... 3

2.1       Http请求刚刚到达服务器的时候... 3

2.2       理解管道(PipeLine) 3

2.3       HttpModule. 4

2.4       HttpHandler. 6

2.5       页生命周期... 7

 

1  .概述

1.1       背景

大部分时候,我们开发人员只关心如何在具体页面中实现需求,但是,了解ASP.NET的运作原理是非常必要的。

1.2       目的

通过对ASP.NET框架中对Http请求处理流程的讲述,让大家理解ASP.NET的运作原理,同时引出HttpModule以及HttpHandler这两个重要概念。

 

2  .Http请求处理流程

2.1       Http请求刚刚到达服务器的时候

当服务器接收到一个 Http请求的时候,IIS 首先需要决定如何去处理这个请求(NOTE服务器处理一个.htm页面和一个.aspx页面肯定是不一样的么)。那IIS依据什么去处理呢?―― 根据文件的后缀名。

打开IIS配置文件,我们能看到,一般地说,所有的.aspx文件实际上都是由 aspnet_isapi.dll 这个程序来处理的,当IIS把对于.aspx页面的请求提交给了aspnet_isapi.dll以后,它就不再关心这个请求随后是如何处理的了。现在我们应该知道:Asp.Net 只是服务器(IIS)的一个组成部分而已,它是一个 ISAPI扩展

2.2       理解管道(PipeLine)

当Http请求进入 Asp.Net Runtime以后,它的管道由托管模块(NOTE:Managed Modules)和处理程序(NOTE:Handlers)组成,并且由管道来处理这个 Http请求。

4. 理解 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页面所完成的业务逻辑。

4.HttpHandler处理完以后,Http请求再一次回到Module,此时Module可以做一些某个工作已经完成了之后的事情。

 

2.3       HttpModule

上一节我们提到了HttpModule,每一个HttpModule就是一个过滤器,每个Http请求在管道中流动时都需要经过各个HttpModule的处理。

一般来说,我们可以将Asp.Net中的事件分成三个级别,最顶层是 应用程序级事件、其次是页面级事件、最下面是控件级事件,事件的触发分别与 应用程序周期、页面周期、控件周期紧密相关。 Http Module 的作用是与应用程序事件密切相关的

下面以身份验证业务为例,说明怎样添加一个Http Module:

类代码可以添加到AppCode中,也可以写在自己单独的命名空间中,如果是在App_Code中,程序集名即为App_Code。

在AppCode中添加新类AuthenticModule.cs,内容如下:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

 

using Business.Entity;

using Headfree.Framework.Authority;

 

    /// <summary>

    ///AuthenticModule 的摘要说明

    /// </summary>

    public class AuthenticModule : IHttpModule 

    {

        public void Dispose(){}

        public void Init(HttpApplication context) 

        { 

            context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute); 

        } 

        void context_PreRequestHandlerExecute(object sender, EventArgs e) 

        { 

            HttpApplication ha = (HttpApplication)sender; 

            string path = ha.Context.Request.Url.ToString(); 

            int n = path.ToLower().IndexOf("login.aspx");

            int m = path.IndexOf("aspx");//判断是否是page

            if (n == -1) //是否是登录页面,不是登录页面的话则进入{} 

            {

                if (m > 0)//在发现不是登陆页面的基础上判断是否是page

                {

                    User user = ha.Context.Session["loginman"] as User;

                    if (null == user)

                    {

                        string url = BasePage.ConvertToBase64(HttpContext.Current.Request.FilePath);

                        url = "/Login.aspx?url=" + url;

                        if (HttpContext.Current.Request.ApplicationPath != "/")

                        {

                            url = ha.Context.Request.ApplicationPath + url;

                        }

                        WebScript.AlertAndRedirect("用户未登录或登录已失效", url, "_top");

                        ha.Context.Response.End();

                    }

                }

            }

        } 

    }

 

此段代码的主要目的就是在PreRequestHandlerExecute事件中附加我们的身份验证方法,这样在真正访问具体页面之前,能够根据是否已经登录选择直接进入或者跳转到登陆页。

注册:

在web.config中添加

    <httpModules>

      <add name="AuthenticModule" type="AuthenticModule,App_Code"></add>

    </httpModules>

注意逗号后面的App_Code即为程序集名。这样就成功添加了一个自定义HttpModule。

 

2.4       HttpHandler

在所有HttpModule都处理完毕之后,ASP.NET还是要根据配置将具体Http请求转发到对应的HttpHandler中处理。我们可以在web.config中添加配置,为某一种类型或某一个特殊的文件名指定HttpHandler:

 <system.web>
    <httpHandlers>
      <add path="*.jpg" verb="*" type="MyNameSpace.MyClass, MyDllName" />
    </httpHandlers>
 </system.web>

HttpHandler代码如下:

public class CustomHandler : IHttpHandler{
    public void ProcessRequest(HttpContext context)  {
       // 处理请求的代码
    }
    public bool IsReusable {
       get { return true; }
    }
}

这就成功地设置为,每一个试图访问jpg格式的图片文件的Http请求都要经过我们自定义的CustomHandler的处理。

我们也可以新增一个HttpHandler,对原来IIS不支持的文件格式进行处理从而达到了扩展的目的。

 

2.5       页生命周期

刚才我们提到了,一般来说,我们可以将Asp.Net中的事件分成三个级别,最顶层是 应用程序级事件、其次是页面级事件、最下面是控件级事件,事件的触发分别与 应用程序周期、页面周期、控件周期紧密相关。作为软件开发人员,我们一般接触的是页面周期,下面对此讲述一二。

生命周期:

最后再来回顾一下Asp.Net中Page页的生命周期,Page中定义了几个事件:

 

总体上讲:一个ASPX页面被请求时,最终的生命周期就是由Page中定义的上述事件(还有一些可重载的回调方法)以及以前提到的HttpApplication类中定义的事件(以相应的回调方法)共同触发或调用,最终叠加形成的一连串处理过程。

如果先不考虑HttpApplication中的事件处理方法(即不考虑我们在Global.ascx.cs中定义的Application_XXX处理方法),Page中的事件(方法)常规触发(调用)顺序为:

01.Page_PreInit

02.Page_Init

03.Page_InitComplete

04.Page_PreLoad

05.Page_Load

06.Page_LoadComplete

07.Page_PreRender

08.Page_SaveStateComplete

09.Page_Unload

这是在Page页面未回发,且不考虑页面子控件的前提下正常的顺序,如果加入页面回发(比如在页面中放一个asp:Button,然后在Button的Click回发事件中加入处理函数)后,顺序稍微有些变化:

01.Page_PreInit

02.Page_Init

03.Page_InitComplete

04.Page_PreLoad

05.Page_Load

06.Button1_Click

07.Page_LoadComplete

08.Page_PreRender

09.Page_SaveStateComplete

10.Page_Unload

不同的地方在于:回发事件Button1_Click在Page_Load后被触发.

最后再把HttpApplication的事件考虑进来,看下叠加后的顺序,不过先别着急,我们先来看一种特殊情况,如果一个asp.net应用根目录下未设置默认页,这时直接浏览根目录,比如http://localhost:2345/ 时,Globl.ascx.cs中定义的Application_XXX方法的调用顺序如下:
2011-05-03 15:01:39 413 Application_Start

2011-05-03 15:01:39 491 Init

2011-05-03 15:01:39 491 Application_BeginRequest

2011-05-03 15:01:39 506 Application_AuthenticateRequest

2011-05-03 15:01:39 506 Application_PostAuthenticateRequest

2011-05-03 15:01:39 506 Application_AuthorizeRequest

2011-05-03 15:01:39 522 Application_PostAuthorizeRequest

2011-05-03 15:01:39 522 Application_ResolveRequestCache

2011-05-03 15:01:39 522 Application_PostResolveRequestCache

2011-05-03 15:01:39 522 Application_PostMapRequestHandler

2011-05-03 15:01:39 522 Application_AcquireRequestState

2011-05-03 15:01:39 537 Application_PostAcquireRequestState

2011-05-03 15:01:39 537 Application_PreRequestHandlerExecute

2011-05-03 15:01:39 553 Application_Error

2011-05-03 15:01:39 553 Application_EndRequest

2011-05-03 15:01:39 569 Application_PreSendRequestHeaders

2011-05-03 15:01:39 569 Application_PreSendRequestContent

可以看到会触发Application_Error事件,即HttpRuntime认为这是一个错误.

紧接着再浏览一个实际存在的页面,如果这时应用程序有严重错误,导致Application关闭(比如web.config配置错误),调用的顺序如下:
2011-05-03 15:03:47 704 Application_BeginRequest

2011-05-03 15:03:47 704 Application_AuthenticateRequest

2011-05-03 15:03:47 766 Application_PostAuthenticateRequest

2011-05-03 15:03:47 766 Application_AuthorizeRequest

2011-05-03 15:03:47 766 Application_PostAuthorizeRequest

2011-05-03 15:03:47 766 Application_ResolveRequestCache

2011-05-03 15:03:47 783 Application_PostResolveRequestCache

2011-05-03 15:03:48 667 Application_PostMapRequestHandler

2011-05-03 15:03:48 667 Application_AcquireRequestState

2011-05-03 15:03:48 683 Application_PostAcquireRequestState

2011-05-03 15:03:48 698 Application_PreRequestHandlerExecute

2011-05-03 15:03:48 745 Page_PreInit

2011-05-03 15:04:02 903 Page_Unload

2011-05-03 15:04:02 903 Application_Error

2011-05-03 15:04:02 918 Application_EndRequest

2011-05-03 15:04:02 996 Application_PreSendRequestHeaders

2011-05-03 15:04:02 996 Application_PreSendRequestContent

2011-05-03 15:04:03 371 Application_Disposed

2011-05-03 15:04:03 371 Dispose

2011-05-03 15:04:03 386 Application_End

对比刚才的顺序,会发现Application_Start及Init没有再次被调用,也印证了文章前面提到的一些结论(Application_Start在整个asp.net应用生命周期内只触发一次),而且从最后的三个输出能知道:应用程序关闭时Application_Disposed,Dispose,Application_End按顺序调用.

再"重新"浏览(指web Server重启)一下正常访问的页面,在不出错也不回发的情况下,顺序如下:
2011-05-03 15:08:11 513 Application_Start

2011-05-03 15:08:11 591 Init

2011-05-03 15:08:11 591 Application_BeginRequest

2011-05-03 15:08:11 591 Application_AuthenticateRequest

2011-05-03 15:08:11 591 Application_PostAuthenticateRequest

2011-05-03 15:08:11 606 Application_AuthorizeRequest

2011-05-03 15:08:11 606 Application_PostAuthorizeRequest

2011-05-03 15:08:11 606 Application_ResolveRequestCache

2011-05-03 15:08:11 606 Application_PostResolveRequestCache

2011-05-03 15:08:11 622 Application_PostMapRequestHandler

2011-05-03 15:08:11 637 Application_EndRequest

2011-05-03 15:08:11 637 Application_PreSendRequestHeaders

2011-05-03 15:08:11 637 Application_PreSendRequestContent

2011-05-03 15:08:11 637 Application_BeginRequest

2011-05-03 15:08:11 637 Application_AuthenticateRequest

2011-05-03 15:08:11 653 Application_PostAuthenticateRequest

2011-05-03 15:08:11 653 Application_AuthorizeRequest

2011-05-03 15:08:11 653 Application_PostAuthorizeRequest

2011-05-03 15:08:11 653 Application_ResolveRequestCache

2011-05-03 15:08:11 653 Application_PostResolveRequestCache

2011-05-03 15:08:11 653 Application_PostMapRequestHandler

2011-05-03 15:08:11 653 Session_Start

2011-05-03 15:08:11 653 Application_AcquireRequestState

2011-05-03 15:08:11 653 Application_PostAcquireRequestState

2011-05-03 15:08:11 653 Application_PreRequestHandlerExecute

2011-05-03 15:08:11 669 Page_PreInit

2011-05-03 15:08:11 684 Page_Init

2011-05-03 15:08:11 684 Page_InitComplete

2011-05-03 15:08:11 684 Page_PreLoad

2011-05-03 15:08:11 684 Page_Load

2011-05-03 15:08:11 684 Page_LoadComplete

2011-05-03 15:08:11 684 Page_PreRender

2011-05-03 15:08:11 684 Page_SaveStateComplete

2011-05-03 15:08:11 700 Page_Unload

2011-05-03 15:08:11 700 Application_PostRequestHandlerExecute

2011-05-03 15:08:11 700 Application_ReleaseRequestState

2011-05-03 15:08:11 700 Application_PostReleaseRequestState

2011-05-03 15:08:11 700 Application_UpdateRequestCache

2011-05-03 15:08:11 700 Application_PostUpdateRequestCache

2011-05-03 15:08:11 700 Application_EndRequest

2011-05-03 15:08:11 700 Application_PreSendRequestHeaders

2011-05-03 15:08:11 700 Application_PreSendRequestContent

2011-05-03 15:08:11 793 Application_BeginRequest

2011-05-03 15:08:11 793 Application_AuthenticateRequest

2011-05-03 15:08:11 793 Application_PostAuthenticateRequest

2011-05-03 15:08:11 793 Application_AuthorizeRequest

2011-05-03 15:08:11 793 Application_PostAuthorizeRequest

2011-05-03 15:08:11 793 Application_ResolveRequestCache

2011-05-03 15:08:11 793 Application_PostResolveRequestCache

2011-05-03 15:08:11 809 Application_PostMapRequestHandler

2011-05-03 15:08:11 809 Application_AcquireRequestState

2011-05-03 15:08:11 809 Application_PostAcquireRequestState

2011-05-03 15:08:11 809 Application_PreRequestHandlerExecute

2011-05-03 15:08:11 825 Application_PostRequestHandlerExecute

2011-05-03 15:08:11 825 Application_ReleaseRequestState

2011-05-03 15:08:11 840 Application_PostReleaseRequestState

2011-05-03 15:08:11 949 Application_UpdateRequestCache

2011-05-03 15:08:11 949 Application_PostUpdateRequestCache

2011-05-03 15:08:11 965 Application_EndRequest

2011-05-03 15:08:11 981 Application_PreSendRequestHeaders

2011-05-03 15:08:11 981 Application_PreSendRequestContent

 

posted @ 2013-02-20 10:26  肖璟  阅读(370)  评论(0编辑  收藏  举报