Http请求过程

一、引言

  工作了好几年,一直在网上查找资料和学习,得到了博客园很多园友的帮助,在积累了一些东西之后,一直也没有系统的总结下来,现在终于下决心来博客园记录这些年的一些知识体系,希望可以坚持下来。

  那么第一篇博文就从.net角度来理解一下http请求从浏览器到达服务器响应的一个过程吧。

二、正文

  当用户在浏览器上输入url地址按下回车键后究竟发生了什么呢?浏览器会像浏览器发送一次请求Request,请求经过的过程可以看下面的这张图。

  可以看到,请求到达域名供应商的DNS服务器,通过DNS解析获取到真实服务器的IP和Port,DNS将请求转发到真正的服务器上,服务器中的Http.sys组件接收到http请求,将其转给IIS处理,IIS根据请求找到对应的w3wp进程(w3wp.exe是在IIS与应用程序池相关联的一个进程,如果你有多个应用程序池,就会有对应的多个w3wp.exe的进程实例运行)。

  IIS根据请求的后缀来决定如何处理请求,当请求的文件为静态文件如以 js/html/htm/css结尾会直接返回。而会将其他后缀的请求转发给 Aspnet_ISAPI 进行处理,当然,如果我们采用MVC的模式请求是不带有后缀的,这个时候IIS6.0会为没有后缀的请求加上一个axd的后缀,而IIS7.0以上的就不需要,因为IIS7.0以上的使用的是UrlRoutingModules扩展来处理MVC请求(IIS7.0以上会看到应用程序池有两种模式:集成模式和经典模式,其中经典模式代表的是旧模式,即兼容IIS 6)。

  当IIS将请求转发给AspNet_ISAPI后,这时候请求就进入了Asp.Net请求处理管道,将由.net来处理该请求并做出响应。aspnet_isapi会将请求封装成HttpWorkerRequest的一个对象传递给HttpRuntime的ProcessRequest方法。这点我们可以从Asp.Net的源码中看到,它们存在于System.Web当中。

// System.Web.HttpRuntime
/// <summary>
///               Drives all ASP.NET Web processing execution.
///           </summary>
/// <param name="wr">
///               An <see cref="T:System.Web.HttpWorkerRequest" /> for the current application. 
///           </param>
/// <exception cref="T:System.ArgumentNullException">
///               The <paramref name="wr" /> parameter is null. 
///           </exception>
[AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)]
public static void ProcessRequest(HttpWorkerRequest wr)
{
    if (wr == null)
    {
        throw new ArgumentNullException("wr");
    }
    if (HttpRuntime.UseIntegratedPipeline)
    {
        throw new PlatformNotSupportedException(SR.GetString("Method_Not_Supported_By_Iis_Integrated_Mode", new object[]
        {
            "HttpRuntime.ProcessRequest"
        }));
    }
    HttpRuntime.ProcessRequestNoDemand(wr);
}
// System.Web.HttpRuntime
private void ProcessRequestInternal(HttpWorkerRequest wr)
{
    HttpContext httpContext;
    try
    {
        httpContext = new HttpContext(wr, false);
    }
    catch
    {
        wr.SendStatus(400, "Bad Request");
        wr.SendKnownResponseHeader(12, "text/html; charset=utf-8");
        byte[] bytes = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>");
        wr.SendResponseFromMemory(bytes, bytes.Length);
        wr.FlushResponse(true);
        wr.EndOfRequest();
        return;
    }
    wr.SetEndOfSendNotification(this._asyncEndOfSendCallback, httpContext);
    Interlocked.Increment(ref this._activeRequestCount);
    HostingEnvironment.IncrementBusyCount();
    try
    {
        try
        {
            this.EnsureFirstRequestInit(httpContext);
        }
        catch
        {
            if (!httpContext.Request.IsDebuggingRequest)
            {
                throw;
            }
        }
        httpContext.Response.InitResponseWriter();
        IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(httpContext);
        if (applicationInstance == null)
        {
            throw new HttpException(SR.GetString("Unable_create_app_object"));
        }
        if (EtwTrace.IsTraceEnabled(5, 1))
        {
            EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, httpContext.WorkerRequest, applicationInstance.GetType().FullName, "Start");
        }
        if (applicationInstance is IHttpAsyncHandler)
        {
            IHttpAsyncHandler httpAsyncHandler = (IHttpAsyncHandler)applicationInstance;
            httpContext.AsyncAppHandler = httpAsyncHandler;
            httpAsyncHandler.BeginProcessRequest(httpContext, this._handlerCompletionCallback, httpContext);
        }
        else
        {
            applicationInstance.ProcessRequest(httpContext);
            this.FinishRequest(httpContext.WorkerRequest, httpContext, null);
        }
    }
    catch (Exception e)
    {
        httpContext.Response.InitResponseWriter();
        this.FinishRequest(wr, httpContext, e);
    }
}

  从源码可以看到,HttpRuntime会完成HttpContext的初始化,然后将其作为参数传递给HttpApplicationFactory创建HttpApplication对象池,HttpApplication处理各种各样的请求。

  到这,请求就进入了asp.net的请求管道中的管道事件,其中最重要的是IhttpHandler和IHttpModule两个对象,我们可以对其做很多扩展。

   至此,我们大概清楚了浏览器发送一条请求后是如何达到我们的服务器了,那么下一篇就来讲一下请求管道里面的各种事件。

原文地址:https://www.cnblogs.com/jesen1315/p/10984008.html