原文链接:http://aspnet.4guysfromrolla.com/articles/011404-1.aspx
作者:Scott Mitchell

简介
   你是否仔细地想过当一个Asp.net Web页面请求到达服务器的时候,服务器端发生了什么?服务器是如何处理到来的请求的?发送给浏览器的HTML是怎么产生的?开发者可能会用什么机制去处理不同阶段的请求呢?这篇文章将对服务器如何处理Http请求进行详细的探讨。

步骤0:浏览器为ASP.NET Web页面产生一个Http请求
   整个过程从为Asp.net Web页产生一个Http请求开始。例如,用户可能会在他的浏览器中输入这篇文章的URL地址,
http://aspnet.4guysfromrolla.com/articles/011404.aspx。然后,浏览器会产生一个Http请求到4Guys的Web服务器,请求指定的文件/articles/011404-1.aspx。

步骤1:服务器接收Http请求
   Web服务器唯一的任务就是接收到来的Http请求,返回一个带有请求资源的Http响应。4Guys Web服务器运行着Microsoft的Internet信息服务(IIS) Web服务器。请求到来时IIS要做的第一件事就是决定怎样处理这个请求,依据是请求的文件扩展名。例如,如果请求的文件扩展名为.asp,那么IIS会将这个请求让asp.dll处理。
   有很多文件扩展名映射到Asp.net引擎。其中包括以下这些:
   .aspx,Asp.net Web页面
   .asmx,Asp.net Web服务
   .config,Asp.net配置文件
   .ashx,自定义Asp.net HttpHandler
   .rem,远程资源
   其他
   在IIS管理界面,你能配置扩展名映射。例如,你能添加自定义的扩展名。也就是说,你能让Asp.net引擎处理.scott文件请求。
   下面这张图阐明了Asp.net Web页请求的步骤0和1。当一个请求到达Web服务器时,它将被发送到适当的位置(也许是asp.dll,对ASP页面请求来说,也许是ASP.NET引擎,对ASP.NET请求来说)依据其请求文件的扩展名。

步骤2:检查ASP.NET引擎
   http://aspnet.4guysfromrolla.com/articles/011404.aspx页的最初请求会到达IIS服务器,然后被发送到ASP.NET引擎,但是下一步发生了什么?ASP.NET引擎经常被提及到ASP.NET HTTP管道,因为进来的请求将通过一系列HTTP模块最终传到HTTP Handler。    
   HTTP模块是一些有权访问进来的请求的类。这些模块能检查进来的请求,作出一些影响内部流的决定。通过指定的HTTP模块后,请求到达某个Http Handler,它的工作是产生发送给浏览器的输出流。下图阐明了一个Asp.net请求流通过的管道。

   Http管道默认包含一些预设的Http模块。这些模块包括:
   OutputCache,处理返回或缓存页面的HTML输出流,如果需要
   Session,装载基于请求的会话状态和Web.config文件里指定的会话方法
   FormsAuthentication,基于窗体认证架构认证用户,如果需要
   其他
   实际上,你可以到Machine.config(位于$WINDOWS$\Microsoft.NET\Framework\$VERSION$\CONFIG)配置文件里寻找<httpModules>元素,你将看到一个详细的哪些模块被使用的清单。下面显示了默认的模块:

<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="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />
  
<add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" />
  
<add name="ErrorHandlerModule" type="System.Web.Mobile.ErrorHandlerModule, 
                                          System.Web.Mobile, Version=1.0.5000.0, 
                                          Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
 />
</httpModules>

   Http Handler位于Asp.net Http管道的终端。它的任务是为请求的资源产生输出流。对Asp.net Web页来说,这意味着呈递Web控件到Html中并且返回这个HTML。对一个Web服务来讲,它将包含执行指定的方法和包装其返回值到一个适当格式化的SOAP响应。(Web服务更多信息请参见:An Extensive Examination of Web Services)
   不同的Asp.net资源使用不同的Http Handler。在machine.config的<httpHandler>块详细的指明了这些默认使用的Http Handler。这个块的条目涉及一些类,要么是Http Handler本身,要么是Http Handler工厂。当Http Handler工厂被调用时它仅仅返回一个合适的Http Handler实例。
   下面显示了在mechine.config中一部分<httpHandler>元素:
<httpHandlers>
  
<add verb="*" path="*.vjsproj" type="System.Web.HttpForbiddenHandler" />
  
<add verb="*" path="*.java" type="System.Web.HttpForbiddenHandler" />
  
<add verb="*" path="*.jsl" type="System.Web.HttpForbiddenHandler" />
  
<add verb="*" path="trace.axd" type="System.Web.Handlers.TraceHandler" />
  
<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory" />
  
<add verb="*" path="*.ashx" type="System.Web.UI.SimpleHandlerFactory" />
  
</httpHandlers>
   认识到我们能创建自己的Http模板和Http Handler,然后通过修改Web服务器上的machine.config文件把它们插入到管道中供所有Web站点使用,或者你可以在指定的Web应用程序的Web.config文件中添加它们。深入讨论使用模板和Handler已经超出本文范围,但你得认识到通过使用它们你能完成一些美妙的事情。例如,你可以使用Http模板来提供一个自定义的URL重写工具,它可以自动把404错误定位到简洁、用户界面友好的URL地址。(请参见:Rewrite.NET - A URL Rewriting Engine for .NET)另一篇关于使用模板的好文章:compressing the generated HTML
   在Mansoor Ahmed Siddiqui的文章HTTP Handlers and HTTP Modules in ASP.NET你能看到一些关于Http模板和Handler非常棒的讨论。

步骤3:产生输出流
   最后一步是使用适当的HttpHandler产生适当的输出流。然后,它反向地通过Http模板最终返回到IIS,IIS把它发送回初始请求的客户。(如果客户是浏览器,那么浏览器会接收到这个HTML然后解析显示它) 
   不同的HttpHandler,不同的输出流,让我们把焦点集中在特殊的HttpHandler - 呈现Asp.net Web页。折回初始的步骤,当一个Asp.net页(.aspx)请求到达IIS时,它被传送至Asp.net引擎。然后它通过一系列模板。该请求最终被传递到PageHandlerFactory,在machine.config的<httpHandler>块中我们有这样的映射:
<httpHandlers>
  
  
<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory" />
  
</httpHandlers>
   PageHandlerFactory类是一个HttpHandler工厂。它的任务是提供一个可处理请求的HttpHandler的实例。PageHandlerFactory做的事情是找到编译好的描述正在被请求的Asp.net Web页面的类。
   如果你是用Visual Studio.NET来创建Asp.net Web页的,你知道Web页是由两个分离的文件组成的:一个.aspx文件,其中包含HTML标记和Web控件;一个.aspx.vb或.aspx.cs文件,其中包含code-behind类(包括服务器端代码)。如果你没使用VS.NET,你可能使用服务器端<script>块来保持服务器端代码。不管你使用何种方法,当Asp.net Web页在改变HTML或Web控件内容之后首次被访问时,Asp.net引擎会创建一个源自System.Web.UI.Page类的类。然后这个被动态创建的类被编译。
   Page类实现IHttpHandler,因此意味着它满足HttpHandler。接下来PageHandlerFactory检查是否已经存在被请求的Asp.net Web页面类的一个已编译版本。如果没有,它将动态创建这个类并编译它。然后,这个类的一些指定的方法被调用,从而产生页面全部的HTML标记。最后这些HTML标记返回给client。(你是否已经注意到当你对HTML或控件内容更改后去访问页面,会有一些延迟?这是因为Asp.net引擎得去重新创建和重新编译ASP.NET Web页的相应的类)

   011404-1.aspx类在它能被调用而产生HTML之前首先应该被PageHandlerFactory创建并编译。页面呈递的过程 ,包括从被请求的Web页中获取HTML标记,已经超出本文范围,在Dino Esposito的The ASP.NET Page Object Model文章里有很好的讨论这方面的技术。
   
结论
   这篇文章我们对Web服务器如何产生Asp.net Web页的过程进行了概括性的叙述。其中包括这些步骤,从client发出一个页面请求开始,最终被请求的Asp.net Web页面类产生需要呈递的HTML。在之间,请求通过IIS到ASP.NET引擎,然后通过一系列模板管道到达相应的HttpHandler。