Windows 操作系统中的 IIS 负责提供互联网服务,一台运行了 IIS 的计算机可以看成是一台 Web 服务器。
Windows XP SP2 中 IIS 主版本号为 5 , Windows 2003 Server 为 6 , Vista 和 Windows Server 2008 为 7 。对于 Windows 2003 Server ,其默认支持的 ASP.NET 版本为 1.1 ,因此必须单独安装 .NET Framework 2.0 以上版本[1] 。
目前, IIS 6 是使用最为广泛的版本, IIS 5 已基本不在 Web 服务器上部署, IIS 6 与 IIS 5 相比在系统架构上有着较大的差异, IIS 7 与 IIS 6 相比,基本架构并没有根本性的变化,但在许多方面有新的增强和改进。本书选择 IIS 6/7 进行介绍,大部分内容也适合于 IIS 5 ,但 IIS 5 一些已过时的特性就不介绍了。
首先,我们来仔细分辨一下三个很容易混淆的基本概念。
8.1.1网站、Web应用程序和虚拟目录
在 IIS 中可以创建网站、 Web 应用程序和虚拟目录,以便与计算机网络上的用户共享信息。“网站”、“ Web 应用程序”和“虚拟目录”这三个概念的关系如 图 8 ‑1 所示。
图 8 ‑ 1 网站,应用程序与虚拟目录
简而言之, 一个“网站(Web Site )”包含一个或多个“ Web 应用程序(Web Application )”,一个Web 应用程序包含一个或多个“虚拟目录(Virtual Directory )”,而虚拟目录则映射到 Web 服务器或远程计算机上的物理目录。
图 8 ‑2 所示为运行 IIS 7 的一个 Web 服务器。
图 8 ‑ 2 IIS 7 中的网站,应用程序与虚拟目录
图 8‑2 中可以清楚地看到此 Web 服务器上有两个“网站”: Default Web Site 和 NewWebSite ,其中 Default Web Site 网站中有三个“ Web 应用程序”: HappyBookShopService 、 HappyBookShopWebSite 和 OnlineAlbum 。而 HappyBookShopWebSite 应用程序下的每一个子文件夹都是一个“虚拟目录”。最顶层的虚拟目录称为“根虚拟目录”, 图 8‑2 中 Web 应用程序 HappyBookShopWebSite 的根虚拟目录为“ /HappyBookShopWebSite ”。
下面逐个剖析这三个概念。
网站是 Web 应用程序的容器,每个网站都有一个唯一的标识,这一标识由它的 IP 地址、端口和可选的主机头/ 主机名 组合而成, Web 服务器根据收到的 HTTP 请求中的这些信息来确定是对哪一个网站的请求 。
在 IIS 7 中,将网站标识称为“ 网站绑定 ”, 图 8 ‑3 所示为 IIS 7 默认网站的“网站绑定”对话框。
图 8 ‑ 3 IIS7.0 中的网站绑定
Web 应用程序是一种在应用程序池( Application Pool )[3] 中运行并通过 HTTP 协议向用户提供信息服务(通常以 HTML 格式表达信息)的软件程序。创建 Web 应用程序时, Web 应用程序的名称将成为网站 URL 的一部分,用户可以通过 Web 浏览器发出针对该 URL 的 HTTP 请求。
使用Visual Studio 创建的“ASP.NET 网站”,其实是一个“Web 应用程序”,它并不等于IIS 中的“网站”。
在 IIS 中,每个网站至少必须拥有一个 Web 应用程序(但不一定是 ASP.NET 应用程序,可以是其他类型的 Web 应用程序),它被称为“根 Web 应用程序” 或“默认 Web 应用程序” ,除此之外,网站还可以包含一个或多个 ASP.NET (或其他种类) Web 应用程序。
在 Windows XP SP2 中,使用 Visual Studio 创建的 ASP.NET 网站发布到本机 IIS 之后都是作为本机默认网站(即“ localhost ”所代表的网站)所承载的 Web 应用程序而运行的。
Windows Server 和 Vista 可以为某个 ASP.NET 应用程序创建一个独立的 IIS 网站,此网站只承载这个唯一的 ASP.NET 应用程序,并且运行在一个独立的应用程序池中。许多商业网站都采用这种方法以获取较高的性能,同时将此网站与 Web 服务器上承载的其他网站相互隔离,以增强 Web 服务器的安全性。
虚拟目录是在 IIS 中指定并映射到本地或远程服务器上的物理目录的目录名称。然后,此虚拟目录名称将成为 Web 应用程序 URL 的一部分,用户可以通过 Web 浏览器向 IIS 请求访问此 URL 所对应的物理目录中的资源。
在 IIS 中,每个 Web 应用程序都必须拥有一个最顶层的虚拟目录,它被称为“根虚拟目录 ”。
在 Visual Studio 中,可以在属性窗口中直接设定 ASP.NET 网站的根“虚拟路径”( 图 8 ‑4 )。
图 8 ‑ 4 ASP.NET 网站的虚拟路径
但要注意,这里设定的“虚拟路径”是 Visual Studio 自带的轻量级 Web 服务器“ ASP.NET Development Server ”的虚拟路径,而非 IIS 中的虚拟路径。如果使用 Visual Studio 完整版本(比如团队开发版),则可以使用一个“发布网站”的功能。在使用此功能发布网站时可以直接指定 ASP.NET 应用程序在 IIS 中所对应的根虚拟目录 图 8 ‑5 )。
图 8 ‑ 5 设定 IIS 中 ASP.NET 网站的根虚拟目录
图 8 ‑5 中将 ASP.NET 网站所对应的 IIS 根虚拟目录设为 MyNewWebSite 。
一个 Web 应用程序可以拥有多个虚拟目录,这些虚拟目录都将成为 Web 应用程序根虚拟目录的子目录。
可以很方便地在 IIS 中创建一个虚拟目录( 图 8 ‑6 )。
图 8 ‑ 6 在 IIS 7 中创建一个虚拟目录
给 Web 应用添加完虚拟目录之后,可以通过以下 URL 访问虚拟目录中的网页
http:// 网站名称 /Web 应用程序根虚拟目录 / 新创建的子虚拟目录 /Web 网页名称
在上面的例子中, Web 应用程序根虚拟目录为“ /MyNewWebSite ”,新加的虚拟目录为“ MyNewVirtualDir ”,它指向“ D:/MyDir ”目录。现假设 D:/MyDir 目录中有一个 ASP.NET 网页(不妨设为 Sample.aspx ),则通过以下 URL 可以访问此网页:
http://localhost/MyNewWebSite/MyNewVirtualDir/Sample.aspx
[1] 建议在 Windows 2003 Server 上安装最新版本的 .NET Framework 以支持一些新技术,比如 AJAX 和 Silverlight 。
[2] 更具体来说,是 Windows Server 的一个系统核心组件: HTTP.SYS 负责这一工作。后面在介绍 IIS 架构时还将介绍 HTTP.SYS 组件。[3]后文将应用程序池作更详细的介绍
[4]“虚拟目录”有时又被称为“虚拟路径”,两者代表同一概念。
[5]对于 Visual Web Developer 速成版,它没有提供“发布网站”的功能,但可以在“复制网站”对话窗口找到相应的按钮完成这一工作。或者更直接些,直接使用 IIS 管理器来完成这一工作。
[6]在 IIS 5/6 中使用“虚拟目录创建向导”来创建虚拟目录,其方法是在 IIS 的某个 Web 应用程序节点上右击,从快捷菜单中选“新建”--> “虚拟目录”命令。 IIS 7 的操作是类似的,但它直接在快捷菜单的第一级中就提供了“添加虚拟目录”的命令。
8.1.2 应用程序池与工作者进程
“应用程序池( Applicaion Pool ) ”是 Windows Server 为提升 Web 服务的性能和可靠性而引入的一个 Web 程序隔离机制。
一个应用程序池可包含一个或多个 Web 应用程序。 ASP.NET Web 应用程序必须运行在一个应用程序池中。
在 Windows Server 中,一个或多个“工作者进程( Worker Process ) ”为应用程序池提供服务,停止一个应用程序池将导致这些工作者进程被关闭,这时,所有发往此应用程序池中 Web 应用程序的 HTTP 请求将收到“ 503 服务不可用”的响应信息。
图 8 ‑7 展示了一台 Web 服务器上正在运行的应用程序池。
图 8 ‑ 7 IIS 7 中的应用程序池
如 图 8 ‑7 所示,本台 Web 服务器上的设置了 3 个应用程序池,每个应用程序池中可运行多个 Web 应用程序,图中 DefaultAppPool 这一应用程序池运行了 5 个 Web 应用程序。每个应用程序池都可以加载特定版本的 .NET Framework ,以对 ASP.NET 应用程序提供支持。在 IIS 7 中,应用程序池有两种运行模式—— 经典模式和集成模式 。
经典模式下, IIS7 应用程序池运行方式同 IIS 6 [1] 。
集成模式下, IIS 7 直接预装载 .NET Framework ,从而为 ASP.NET 应用程序提供了更好的性能。
在 IIS 管理器中可以随时启动和停止某个应用程序池。
Windows Server 上运行应用程序池的系统帐号是“ NetworkService ”。在后面的章节中可以看到在部署 ASP.NET 网站时往往需要给此帐号设置特定的权限(比如允许 ASP.NET 应用程序向某文件夹中添加文件)。
下面深入介绍一下 IIS 的系统架构以及 Windows Server 是如何响应 HTTP 请求的。
8.1.3 IIS的系统架构
IIS 6 (运行于 Windows 2003 Server )的架构如 图 8 ‑8 所示。
图 8 ‑ 8 IIS 6 的架构
从 图 8 ‑8 中可以看到, IIS 6 架构由以下几个部分组成:
(1)HTTP.SYS :运行于 Windows 核心( Kernel )的一个组件,它负责侦听( Listen )来自于外部的 HTTP 请求(通常来自网络中另一台计算机上的浏览器),根据请求的 URL 将其转发给相应的应用程序池,由运行于应用程序池中的工作者进程来响应此 HTTP 请求。当此 HTTP 请求处理完成时,它又负责将处理结果发送出去(其接收者通常为发出 HTTP 请求的浏览器)。
为了提供更好的性能, HTTP.SYS 内部建立了一个缓冲区,将最近的 HTTP 请求处理结果保存起来,如果发现某个 HTTP 请求“不久以前”处理过了(即在缓冲区中可以找到),它就简单地直接从缓冲区中取出这些结果发回给客户端(通常为发出 HTTP 请求的浏览器)。
(2)InetInfo :在 IIS 5 时代, InetInfo 是 IIS 服务的主进程,在 IIS 6 中,它不再负责处理 HTTP 请求,但它继续负责管理除了 WWW 服务之外的其他互联网服务,比如用于文件传输的 FTP 服务和用于邮件收发的 SMTP 服务。
InetInfo 内部维护了一个元数据库( Metabase ),在这个数据库中存入了一些重要的信息,这些信息对于维护各种互联网服务(比如 WWW 和 FTP )等是必不可少的。
(3)Worker Process :负责处理 HTTP 请求,被译为“工作者进程 ”,事实上,它是由一个可执行程序 W3WP.EXE 运行时所生成的一个进程[ 2] ,每一个工作者进程内部都可以管理一个或多个 ASP.NET 应用程序。 工作者进程运行于一个应用程序池( Application Pool )中。 IIS 6 可以创建多个应用程序池,并指定某个 ASP.NET 应用程序在特定的应用程序池中运行( 图 8 ‑9 )。
图 8 ‑ 9 设定 ASP.NET 网站所属的应用程序池(图截自 Windows 2003 Server )
一般情况下,一个应用程序池只有一个工作者进程,但也可通过配置必要的参数让多个工作者进程同时运行在同一个应用程序池中,在这种情况下,这个应用程序池被称为“ Web Garden ( Web 园) ”。
(4)WAS ( Web Admin Service ) :这是一个监控程序,它一方面可以存取放在 InetInfo 元数据库( Metabase )中的各种信息,另一方面也负责监控应用程序池( Application Pool )中的工作者进程的工作状态况,必要时它会关闭一个老的工作者进程并创建一个新的取而代之。
[1] IIS 6 中应用程序池的运行方式后文有详细介绍
[2]“进程( Process )”是一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程。如用通俗的语言来表达,可以简单地将“进程”理解成一个正在运行的程序。
8.1.4 HTTP请求的处理过程
在了解了 IIS 的架构之后,来看一下 IIS 架构中的各个组成部分是如何相互配合处理 HTTP 请求的。
先来从总体上看看 HTTP 请求的处理过程( 图 8 ‑10 )。
图 8 ‑ 10 HTTP 请求的处理过程
图 8 ‑10 清晰地展示出了 HTTP 请求处理就是浏览器与 Web 服务器间“一问一答”的过程 。
首先,浏览器尝试连接 Web 服务器的 80 端口,如果 Web 服务器可以响应此连接请求,就在浏览器与 Web 服务器间建立了一个通讯链路,在此“通道”上浏览器与 Web 服务器可以相互发送与接收信息。
假设浏览器向 Web 服务器发出一个读取某 ASP.NET 站点上的某个 ASPX 网页的请求。当此请求通过网络到达 Web 服务器时,此请求被 HTTP.SYS 组件所接收。 HTTP.SYS 系统组件会检查此 HTTP 请求的相关信息,根据其 URL 将此 HTTP 请求发送给运行在某个应用程序池中的工作者进程处理。如果同时有多个针对此 ASP.NET 站点的 HTTP 请求, HTTP.SYS 会将这些请求排队,加入到对应的应用程序池的 HTTP 请求队列中等待。
如果这是第一个对 ASP.NET 站点的 HTTP 请求,工作者进程会加载 aspnet_isapi.dll ,并将请求转给它, aspnet_isapi.dll 接着会装载 .NET CLR[1] , 创建一个针对此 ASP.NET 站点的应用程序域[2] ,然后启动一个复杂的由多个步骤和组件参与的处理流程,当此处理流程结束,要发回给客户端的结果(通常是 HTML 代码,当然也可以是其他类型的资源,比如由程序动态生成的图片)已经生成,此结果被转发给 HTTP.SYS 。
注意: 对于以集成模式运行的IIS 7 ,.NET CLR 在应用程序池一启动就自动装载,从而避免了临时装载CLR 的花销。后继处理过程与IIS 6 基本一致。
HTTP.SYS 接收到请求的处理结果之后,将其缓存到缓冲区中,然后把处理结果发回给发出 HTTP 请求的浏览器。
上述过程是对 IIS 处理 HTTP 请求全过程的粗略描述。 8.2 节将选取这个处理过程中的主要阶段,详细介绍针对 ASP.NET 网页的 HTTP 请求处理过程。
在 IIS 的文档中经常会提到两个术语: ISAPI 扩展和 ISAPI 筛选器。
“ ISAPI 扩展( ISAPI Extension ) ”是一种可以添加到 IIS 中以增强 Web 服务器功能的程序,其载体为 DLL 文件。它通常直接负责响应 HTTP 请求。
根据 HTTP 请求要访问的资源扩展名(通过 URL 获取), IIS 会选取特定的 ISAPI 扩展来处理这一请求,这一过程被称为“ 程序映射 ” 。 而用于响应 HTTP 请求的这一 ISAPI 扩展被称为“ HTTP Handler (HTTP 处理程序) ”。 图 8 ‑11 展示了 IIS 6 中的程序映射。
图 8 ‑ 11 程序映射( IIS 6 )
在 图 8 ‑11 中可以看到, IIS 指定对 ASP.NET 网页(其扩展名为 .aspx )的请求将由 aspnet_isapi.dll 处理( 图 8 ‑12 )。
图 8 ‑ 12 aspnet_isapi.dll 负责处理对 ASP.NET 网页的请求
IIS 7 中的程序映射与 IIS 6 略有不同。当 IIS 7 以“经典模式”运行时,与 IIS 6 一样使用 aspnet_isapi.dll 响应针对“ .aspx ”的请求。但当 IIS 7 以“集成模式”运行时,则使用托管处理程序( System.Web.UI.PageHandlerFactory )响应针对“ .aspx ”的请求( 图 8 ‑13 )。
图 8 ‑ 13 IIS 7 集成模式下的程序映射
“ISAPI筛选器(ISAPI Filter ) ” 也是一种 DLL ,但它不负责生成 HTTP 请求,它的主要作用是响应某些特定的事件。当这些事件发生时 ISAPI 筛选器被调用,它可以修改传入或传出的 HTTP 数据。
在 IIS 7 中,使用“ HTTP 模块(HTTP Module ) ” 取代了传统 ISAPI 筛选器的功能。
注意: ISAPI 扩展与ISAPI 筛选器名字很相近,但其在IIS 中的地位和所起的作用是不同的。
[1] CLR ( Comon Language Runtime ):通用语言运行时,是 .NET 的核心,可以将其看成是一台虚拟的专用于运行 .NET 程序的计算机。
[2] 应用程序域( Application Domain ): .NET 引入的一种代码隔离机制,一个托管进程可以拥有多个应用程序域,在应用程序域中可以装载程序集,创建特定类型的对象,调用对象的方法。
8.1.5 ISAPI扩展、ISAPI筛选器和程序映射