zoukankan      html  css  js  c++  java
  • 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两个对象,我们可以对其做很多扩展。

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

  • 相关阅读:
    Android-自定义meta-data扩展数据
    (转载)【Android】ViewGroup全面分析
    小问题记录
    Gson使用 .Net中的日期序列化成带字母T的格式,Gson发序列化问题
    Android中自定义textview可以进行自体设置
    .Net版的BeanUtils
    Ksoap2-android 添加网络超时的实现
    Html5 viewport 解释
    计算两个日期之间相差的月数
    Android中的Adapter内,有getView方法
  • 原文地址:https://www.cnblogs.com/jesen1315/p/10984008.html
Copyright © 2011-2022 走看看