在学习Asp.net时,发现大多数作者都是站在一个比较高的层次上讲解Asp.Net。 他们耐心、 细致地告诉你如何一步步拖放控件、 设置控件属性、编写 CodeBehind代码,以实现某个特定的功能。这种做法,实际上是回答了“如何去做”的问题,却没有回答“为什么可以这样做”的问题。这样有它的好处, 就是可以快速开发。 但建议多掌握一点底层知识,对一些问题会有更好的理解。希望通过这篇文章的,可以让你更好的理解IIS和 Asp.Net的运作原理。
思考“为什么在地址栏输入 www.baidu.com就可以看到百度主页?”类似于思考“为什么苹果是往地上掉不是往天上飘?”。 对于普通访问者来说, 这就像每天太阳东边升起西边落下一样是理所当然的。 对于很多程序员来说, 认为这个与己无关,不过是系统管理员或者网管员的责任。毕竟,IIS 是Windows的一个组件,又不是Asp.Net的一个组成部分。而实际上,从你轻拍回车到页面呈现在你眼前的十分之一秒内,IIS 和.Net Framework已经做了大量的幕后工作,并且在IIS7.0以后的版本中Asp.net已经成为IIS的核心。
一、初识IIS
IIS全称为Internet Information Server(网络信息服务管理器),它是微软公司主推的Web服务器。也就是说在理解IIS时首先我们应该把我们的电脑看做是一个网络服务器,而IIS就是管理网络信息的服务器管理程序。
IIS有了基本的理解后我们再来看一个完整的网络请求,如下图:
客户端在请求网页时首先要在网页中输入静态的IP地址或者网站域名,经过域名解析后如果请求的地址存在且合法则请求的内容会发送到服务器上。当服务器接收到一个 Http 请求的时候,IIS 首先需要决定如何去处理这个请求(如:服务器处理一个.htm 页面和一个.aspx页面肯定是不一样的么)。那 IIS 依据什么去处理呢?答案是:根据文件的后缀名。
服务器获取所请求的页面(也可以是文件,如:sun.jpg)的后缀名以后,接下来会在服务器端寻找可以处理这类后缀名的应用程序, 如果 IIS找不到可以处理此类文件的应用程序,并且这个文件也没有受到服务器端的保护(如:一个受保护的例子就是App_Code中的文件, 一个不受保护的例子就是你的js脚本),那么 IIS 将直接把这个文件返还给客户端,如果IIS找到可处理的此类文件的应用程序后会使用托管代码对它进行编译,然后在返回到管道继续执行,最后返还回客户端。
能够处理各种后缀名的应用程序,通常被称为ISAPI(在下面我们会讲到)应用程序。虽然这ISAPI听上去还挺气派,也算是“应用程序”呢,但仔细看看它的全称就明白了,它实际上只是一个接口,起到一个代理的作用,它的主要工作是映射所请求的页面(文件)和与此后缀名相对应的实际的处理程序。
现在我们对网络请求有了初步的认识,但是还有很多疑问。IIS在收到HTTP请求后是如何对信息进行解析处理的,它内部的工作原理又是什么样的。不要着急,接下来我们马上说明。
二、再看IIS
首先来看下IIS的基本构成。
在向下解析IIS前我们要先认识些专有名字,这些名词都是IIS内重要的组成部分。
1、何为请求管道
对于IIS的初级开发人员来说,请求管道是一个很新的名词,它的作用和我们平常生活中所看到的管道是相同的,IIS在运行时会在应用程序池中创建一个运行管道,这个管道把HTTP的请求服务集成到了一起。
那么这个请求管道就是集成了HTTP请求所需要的所有步骤的内容。ASP.NET使用的就是管道模式来处理的HTTP请求。
2、何为托管代码
托管是NET的一个专门概念,它是一种编程理念,使用托管实现了对程序语言的相互转化,可以说它是一种中间语言,等同于我们现实生活中的翻译器,实现了编程语言的通用转换,因此完全可以把“托管”视为“.NET”。
托管代码也是如此,简单点说,托管代码是微软的中间语言,他主要的作用是在.NET的CLR执行代码前去编译源代码,也就是说托管代码充当着翻译的作用,源代码在运行时分为两个阶段:
① 源代码编译为托管代码;(所以源代码可以有很多种,如VB,C#);
② 托管代码编译为微软系统的.net平台专用文件(如类库、可执行文件等)。
它就好像是我们现实生活中的翻译人员,两个国家之间的语言往往是不同的,但是为了实现交流就必须由翻译人员实现语言托管。
3、何为ISAPI
ISAPI是网络服务应用程序接口,全称是Internet Server Application Programming Interface。仔细看看它的全称就可以明白,它实际上只是一个接口,起到一个代理的作用。
ISAPI主要分为ISA和ISAPIFilter两部分。ISA方法相对而言要传统一些,利用一些特殊的链接,指向服务器的作业,供程序开发人员设计一些扩展功能;而ISAPI过滤器则倾向于构造服务器直接调用的模块,提供一种无缝链接部件用于监测直接来自于服务器的HTTP请求。
简单的讲,ISAPI我们可以理解为一种语言编译器。asp.net或其它程序语言文件,如:PHP、JSP等传输到ISAPI后,根据文件扩展名的不同映射所请求的页面(文件),让与此后缀名相对应的实际的处理程序来接管。由应用程序接管的,扩展名为.exe;由应用程序扩展接管的,扩展名为.dll。这种托管需要获取指定语言的映射机制,一般为DLL文件,例如:ASP对应的ISAPI映射为:"%SYSTEMROOT%\inetsrv\asp.dll"。
在我们日常生活中这种请求机制随意可见,公司的部门的分配就是很好的实例典范。当一项业务分配到该公司后,公司老板会根据业务的不同来指定部门处理请求,老板分配业务就是一种映射关系,各个部门收到指令后去处理业务就是一种代码的托管机制。
三、解读IIS内部运行机制
IIS7.0提供了两种管道的托管模式,它们分别是:经典管道模式和集成管道模式。经典管道模式是IIS7.0以前的请求模式,这种模式扩展繁琐,运行效率也比较低下。IIS7.0发生了翻天覆地的变化,就连底层的代码库也是重新进行编写的,但是微软为了IIS的兼容性,仍然为用户保存了经典的托管模式。
如下图为IIS两种托管模式的运行机制:
1、经典管道托管模式
图1中采用的是经典管道托管模式,HTTP进入请求管道后首先要进行身份验证,验证方式有多种,验证完成后要确定执行处理程序,如果这个文件是一个ASP.NET文件,将执行托管,退出请求管道转入ASP.NET ISAPI过滤器。通过ISAPI的处理后,这个请求还将返回管道,然后在向下请求管道,执行发送响应,写入请求日志,并将请求信息发送给客户端。
图1中,ASP.NET扮演了一个ISAPI过滤器的角色(ASP.NET只是ISAPI的一个插件),也就是说,请求退出管道后,由aspnet.dll进行处理,然后返回到管道进行进一步处理,最终将响应返回给客户端。
这种经典的托管模式有很多缺点,其一,扩展繁琐,开发人员要自己编写程序运行所需要的ISAPI过滤器,但对于一般的程序猿来说这是很困难的时;其二,执行效率低,在执行ISAPI过滤时要退出请求管道运行应用程序实现过滤,增加了应用程序个数,浪费了内存空间;其三,安全性差。其中最主要的是安全问题,它在运行时要退出管道,查找映射,如果被影射的DLL文件不存在,则不能向下执行,导致执行出错(常见的错误如:映射出错)。虽然这种托管模式已被修改,但是IIS 7.0继续提供了这种模式,主要是考虑到程序兼容性问题,如果在集成模式下不能使用,可以迁移到经典模式中。
2、集成管道托管模式
要想深入理解集成管道模式的好处,首先我们要了解集成的概念,集成是说把某一模块能够作为处理的一个步骤加入其中,而且这种集成是非常灵活的,开发人员可以任意指定要集成的托管代码,如:ASP.NET、PHP等。
此时在看集成的优势就会发现,集成模式不仅增强了IIS的灵活性,而且使得HTTP请求模式更加安全。其一,集成模块的托管代码可以由开发人员自行制定,并且模块可以成为管道的组成部分;其二,它去除了复杂的ISAPI的映射托管过程,在请求时可以 直接由相应的编译环境来执行请求,使得编译过程更加安全。ASP.NET的性能之所以能够得到改善,也是因为ASP.NET应用程序集成到管道中,在请求时不再需要退出管道并加载ISAPI进程来处理ASP.NET代码,然后再返回到管道为客户提供响应信息。
如果我们把ASP.NET集成到IIS管道中,那么此时ASP.NET就成为IIS7.0的核心。可以在管道中处理ASP.NET文件,这样可以在处理过程的任意一个步骤使用ASP.NET代码。因为ASP.NET已经成为管道的一部分了。所以,诸如身份验证之类的ASP.NET功能也可以用于处理非ASP.NET内容(如:StaticFile、Image、HTML等)。每个请求都可以由IIS和ASP.NET进行处理,而不必考虑其所属类型。
四、应用程序池、应用程序和虚拟目录
管道模式是针对应用程序池的,IIS在工作时会在应用程序池中创建请求管道,简单的讲应用程序池是用来存放请求管道的。在创建网站时会创建一个应用程序我们称之为根应用程序,使用(/)表示,同时也默认创建该网站的应用程序池,但是我们也可以为请求管道随意指定应用程序池,同时也修改了应用程序所在的应用程序池。也就是说应用程序的执行是基于HTTP请求管道的。
虚拟目录是一个指针,它指向了本地物理地址或者远程服务器上的某个地址。在创建应用程序时会默认创建一个虚拟目录,那就是应用程序所指的根虚拟目录,也用(/)表示。
应用程序是由一些文件和文件夹组成的集合,这些文件和文件夹可以通过诸如HTTP或HTTPS等协议为外界提供服务。一个应用程序下可以指向多个本地物理地址,也就是可以创建多个虚拟目录。
一个应用程序池中可以包括多个应用程序。每个网站至少包括一个应用程序(一个网站就是一个应用程序),即根应用程序,但是在必要情况下,一个网站可以包括多个应用程序。
它们之间的关系如下图:
所以它们四者的关系就很明显了应用程序池-->HTTP管道-->应用程序-->虚拟目录。
这种关系就相当于Windows系统中的文件夹和快捷方式之间的关系,我们可以把磁盘看做一个应用程序池,文件夹看做一个应用程序,而虚拟目录就相当于文件夹内的快捷方式。如果我们想要在文件夹中访问一个文件但又不想让文件保存在文件夹下,这时我们可以通过快捷方式来实现。我们通过快捷方式能够实现快捷访问文件夹中的内容,且不用指定安全级别。