IIS 关于 Http 请求的处理流程
一、HTTP请求处理流程的基础
1.网络分层
关于网络分层,请查看本人的另一篇博客:网络分层。
2.端口
在网络上,各主机间通过TCP/IP协议发送和接收数据包,各个数据包根据其目的主机的IP地址来进行互联网络中的路由选择,把数据包顺利的传送到目的主机。大多数操作系统都支持多程序(进程)同时运行,那么目的主机应该把接收到的数据包传送给众多同时运行的进程中的哪一个呢?显然这个问题有待解决,端口机制便由此被引入进来。
本地操作系统会给那些有需求的进程分配协议端口(protocol port,即我们常说的端口),每个协议端口由一个正整数标识,如:80,139,445,等等。当目的主机接收到数据包后,将根据报文首部的目的端口号,把数据发送到相应端口,而与此端口相对应的那个进程将会领取数据并等待下一组数据的到来。
端口其实就是队,操作系统为各个进程分配了不同的队,数据包按照目的端口被推入相应的队中,等待被进程取用。在极特殊的情况下,这个队也是有可能溢出的,不过操作系统允许各进程指定和调整自己的队的大小。
不光接受数据包的进程需要开启它自己的端口,发送数据包的进程也需要开启端口,这样,数据包中将会标识有源端口,以便接受方能顺利地回传数据包到这个端口。
3.网站、应用程序、虚拟路径
关于网站、应用程序和虚拟路径,请查看本人的另一篇博客:网站、应用程序、虚拟路径。
4.IIS配置
(1)配置文件所在位置:%windir%\system32\inetsrv\config\applicationHost.config
(2)<sites>节点下的集合与元素的层级关系
(3)<applicationDefaults>与<virtualDirectoryDefaults>的意义
<applicationDefaults> 的父元素不同时,其所指的意义也不同:
-
- 父元素<sites> section:指定服务器上的所有应用程序的默认设置。
- 父元素<site> collection:指定网站上的所有应用程序的默认设置。
<virtualDirectoryDefaults>的父元素不同时,其所指的意义也不同:
-
- 父元素<sites> section:指定服务器上所有的虚拟目录的默认设置。
- 父元素<site> collection:指定网站上所有的虚拟目录的默认设置。
- 父元素<application> collection:指定应用程序下所有的虚拟目录的默认设置。
二、IIS架构
关于 IIS 架构,请查看本人的另一篇博客:IIS 架构。
节选《IIS 架构》:在HTTP请求处理上,工作流程可以简单地说成是这样子:
- 配置改变时,被WAS(应用程序池和工作者进程的管理者)读到,并update到WWW Service(监听适配器);
- WWW Service又将新配置信息配置update到HTTP.SYS(协议监听程序);
- HTTP.SYS接收到请求时,将请求直接给了W3WP.exe(工作者进程);
- 工作者进程处理请求后,将响应返回到HTTP.SYS【WWW Service、WAS等不直接接触Http请求】。
三、处理流程
1.流程步骤
IIS 7 及更高版本与IIS 6 有类似的请求处理流程。
(1)客户端请求一个在服务端的资源,HTTP.SYS监测到请求。
此时,http.sys检查请求是否合法,如果不合法,返回给客户端一个错误代码。
如果合法,http.sys检查是否请求静态内容,如果是,立即返回给客户端。
如果是请求动态内容,http.sys检查是否有对应响应的缓存,如果有,立即返回给客户端。
如果没有缓存,http.sys将请求放置在“队列”里。(可直达步骤7)
(2)HTTP.SYS联系WAS,令其获取配置信息。
(3)WAS从配置仓库(applicationHost.config)读取配置信息,并update到WWW Service。
(4)WWW Service接收到配置信息,比如应用程序池和网站配置。
(5)WWW Service将配置信息update到HTTP.SYS。
(6)WAS启动一个工作者进程,该工作者进程将处理HTTP.SYS监测到的请求。
(7)HTTP.sys根据Update到的配置信息,直接将请求【丢给相应的工作者进程】,工作者进程处理请求后,将响应返回到HTTP.SYS。
工作者进程从“队列”中取出请求,开始处理请求。它先评估请求的URL,判断请求的类型(ASP,ISAPI,CGI等)。最后将响应返回给http.sys。
(8)HTTP.SYS将请求返回到客户端,客户端接收到响应。
2.工作者进程中步骤
【集成模式】在工作者进程中,HTTP请求”将穿过一组有序的步骤【被称为“事件】。关于 事件,请查看本人的另一篇博客:HttpModule订阅管道事件。
在每个事件中,本地模块(native module)处理请求的一部分(比如验证用户和添加事件日志);如果一个请求需要托管模块来处理,本地模块 ManagedEngine 将创建 AppDomain ,在该AppDomain中,托管模块继续执行请求的处理。集成模式允许我们在ASP.NET中编写一些功能(Module)来改变IIS的行为(扩展)。
当请求穿过所有的事件,响应将返回到HTTP.SYS。
3. 进入AppDomain以后
关于什么是AppDomain,请查看本人的另一篇博客:什么是AppDomain。
(1)托管模块中
当Http请求进入AppDomain以后,它的管道由托管模块(Managed Modules)和处理程序(Handlers)组成,并且由管道来处理这个Http请求:
自定义的托管模块HttpModule通过在某些事件中注册,把自己插入ASP.NET请求处理管道(因为管道合并,同时也是IIS管理)。当这些事件发生的时候,则会调用对相应的HttpModule,这样该自定义的托管模块就能处理请求了。
public class TestModule : IHttpModule { public void Dispose() { throw new NotImplementedException(); } public void Init(HttpApplication context) { //向HttpApplication订阅BeginRequest事件 context.BeginRequest += Context_BeginRequest; } private void Context_BeginRequest(object sender, EventArgs e) { HttpApplication httpApplication = (HttpApplication)sender; httpApplication.Response.Write("你的请求被我在mould中改了"); } }
<configuration> <system.web> <httpModules> <add name="TestModule" type="TestPermission.PermissionHttpModule,TestPermission"/> </httpModules> </system.web> </configuration>
(2)Handler中
Http请求经过所有的Module之后,它会被HttpHandler处理。一个请求对应一个HttpHandler。
在http请求的处理过程中,只能调用一个HttpHandler,但可以调用多个HttpModule。所以,一旦定义了自己的HttpHandler类,那么它对系统的HttpHandler的关系将是“覆盖”关系。
public class TestHandler : IHttpHandler { public bool IsReusable => true; public void ProcessRequest(HttpContext context) { throw new NotImplementedException(); } }
Web.Config配置文件:
<httpHandlers> <add verb="*" path="*" type="ClassLibrary831.TestHandler,ClassLibrary831"/> </httpHandlers>