第一步:用户在地址栏里面输入地址,或者是提交表单
第二步:浏览器内部会将请求封装成HTTP请求报文,并建立Socket连接发送HTTP请求到服务器端
第三步:等待服务器端响应
服务器端:
1、内核模块
1.1 内核模块(HTTP.SYS)监听80端口
1.2 监听到客户端的连接,并解析出请求的协议以及访问的端口
1.3 查询注册表,并将此请求交给具体处理的进程(默认IIS会注册此过滤模块),此时请求分发给IIS
2、IIS模块
2.1 请求来了之后,IIS首先进行校验请求的身份
2.2 检查请求的文件的后缀,如果是静态文件则直接处理返回(比如:js,html,css,png等)
2.3 如果是IIS处理不了的动态文件,则直接将请求交给扩展处理程序(比如:.aspx,.ashx,.ascx请求交给aspnet_isapi.dll处理【aspnet_isapi.dll是在.Net Framework安装的时候注册的。如果是先安装.Net Framework 后安装IIS可以使用命令:aspnet_regiis -i来进行安装(在cmd和vs的命里行里面都要执行一下)】)
IIS内部执行的过程:请求从内核拿到后,交给了w3svc服务,然后此服务去 问IIS要元数据信息,当前请求交给哪个扩展处理。
3、工作进程阶段(workprocess)IIS6:w3wp.exe IIS5:aspnet_wp.exe
下面写的都是针对IIS6和IIS7经典过程:
3.1 请求先到扩展模块:aspent_isapi.dll(这是一个非托管的程序集,微软写的一个实现了IIS扩展接口的一个COM的程序集。并且已经注册到 了IIS的扩展中),它是非托管环境和托管环境的桥梁,它负责将请求的报文数据交给aspnet runtime,另外负责将aspent处理后的响应交还给IIS。另外此扩展会负责第一次请求来的时候,启动aspent 的runtime(appdomain等)
以下是托管环境中的代码(我们可以看到所有的源码)
3.2 请求到达ISAPIRuntime
此时请求交给public int ProcessRequest(IntPtr ecb, int iWRType)方法处理,其中第一个参数:ecb是windows操作系统的一个句柄,
句柄的概念:句柄是windows操作系统特殊的标识,代表着操作系统的一个资源,32位操作系统是一个32位的数字,而64位的那就是64位的(了解即可);
ecb非常niublity。拿到ecb后就可以拿到请求报文的所有的东西,在ProcessRequest方法内部,通过ecb创建了一个 HttpWorkRequest实例【HttpWorkRequest是一个很原始的对HTTP请求报文做了简单封装,另外封装了对ecb返回数据的封 装,也就是说请求都会从这里获得,响应也是从这里返回】
3.3 请求交给HttpRuntime类
请求交给HttpRuntime的private void ProcessRequestInternal(HttpWorkerRequest wr)
第一步:通过HttpWorkerRequest创建HttpContext上下文,此上下文会在整个Appliaction管道中流动,而且是线程安全的,HttpContext包含了HttpRequest对象和HttpResponse对象,它们分别封装了Http请求的请求报文以及响应的信息。
第二步:获取Appliaction实例
HttpRuntime自己不处理当前请求,而是交给一个代理对象HttpAppliaction实例。
HttpAppliaction实例是通过如下代码获取的:
IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);
我们看到了这是做了一个对象池技术,因为HttpAppliaction创建是通过将aspnet项目里面的Global.asax编译成 HttpAppliaction类型,然后通过反射创建出来,所以实例很宝贵,创建非常浪费性能,微软为了提高性能,使用对象池技术,使得 HttpAppliaction得到了重用。在源码内部我们看到了对象池使用了lock栈进行了管理。可以看一下反射的代码:
private HttpApplication GetNormalApplicationInstance(HttpContext context)
{
HttpApplication application = null;
lock (this._freeList)
{
if (this._numFreeAppInstances > 0)
{
application = (HttpApplication) this._freeList.Pop();
this._numFreeAppInstances--;
if (this._numFreeAppInstances < this._minFreeAppInstances)
{
this._minFreeAppInstances = this._numFreeAppInstances;
}
}
}
if (application == null)
{
application = (HttpApplication) HttpRuntime.CreateNonPublicInstance(this._theApplicationType);
using (new ApplicationImpersonationContext())
{
application.InitInternal(context, this._state, this._eventHandlerMethods);
}
}
return application;
}
在此还做了处理,如果是第一次请求的话,则首先初始化特殊的应用程序池,然后创建一个