URL解析过程

  在详细解读一次完整的URL解析过程的中,首先们我们需要了解一些基础性的知识和概念,如什么是RUL,什么是DNS?下面来分别进行介绍。

  URL(Uniform Resource Locator): 统一资源定位符,URL是使用浏览器访问web页面时需要输入的网页地址。如:https://www.baidu.com/就是URL.也被称为“网址”。

  我们首先看一下https://www.bilibili.com/?spm_id_from=333.851.b_7265706f7274466972737431.1这个网址的组成部分

    1.协议部分:http协议(超文本传输协议),这个协议支持简单的请求和响应会话用于客户端和

服务器之间的通信。除HTTP协议外,还有HTTPS(比http更安全),ftp协议(文件上传下载协议)等。上面网址用的是:https。

    2. 服务器域名:它可以分为*域名,一级域名,二级域名。上面网址用的是:bilibili.com

    3:端口号:端口是服务器用于内外部通信的通道,当用户访问服务器时必须从要求的端口访问才能正常打开网页。上面用的是端口号是80,可以省略默认。

    4. 问号传参:客户端想把信息传递给服务器,可以基于问号传参进行处理。还可以用于客户端一个页面跳转到另一个页面,在新的页面中获取到旧页面的某些内容,也是可以基于问号传参来实现。也可以用于组件传参。上面用的是:?spm_id_from=333.851.b_7265706f7274466972737431

  与URL相比,还有URI(Uniform Resource Identifier) 统一资源标识符。URI就是由某个协议方案表示的资源的定位标识符。协议 方案是指访问资源所使用的协议类型名称。

  一次url解析要分为以下几步,1.url解析 2. DNS解析 3. 建立TCP链接 4. 发送HTTP请求 服务器处理 5. 关闭TCP连接通道 6. 客户端渲染。如下图所示;

URL解析过程

  下面我们来分别进行解析:

  一. url解析 

  在一次完整的url解析中有以下几步分别是:地址的解析和编码 ,HSTS,缓存检查...

  1.地址的编码和解码   

    JS的编码和解码有三种方式:

     encodeURI()/decodeRUI(): 这两个函数把字符串作为URI进行编码/解码,实际上encodeURI()函数只把参数中的空格编码为%20,汉字进行编码,其余特殊字符不会转换。

    <script>
        let str = "www.baidu.com/davina /微信";
        console.log(encodeURI(str)); //www.baidu.com/davina%20/%E5%BE%AE%E4%BF%A1

        let str1 = "www.baidu.com/davina /微信/ac1";
        console.log(encodeURI(str1)); //www.baidu.com/davina%20/%E5%BE%AE%E4%BF%A1/ac1
    </script>

     encodeURIComponent()/decodeURIComponent(): 这两个函数可把字符串作为URI组件进行编码/解码。由于这个方法对:/都进行了编码,所以不能用它来对网址进行编码,而适合对URI中的参数进行编码/解码。

    <script>
      let uri = "https://www.davina/com/from=http://wwws.baidu.com";
      console.log(encodeURIComponent(uri)); //https%3A%2F%2Fwww.davina%2Fcom%2Ffrom%3Dhttp%3A%2F%2Fwwws.baidu.com

      //所以一般我们的用法是:
      let newUri = `https://www.davina/com/from=${encodeURIComponent(
        "https://www.baidu.com"
      )}`;
      console.log(newUri); //https://www.davina/com/from=https%3A%2F%2Fwww.baidu.com
    </script>

     escape()/unescape(): 函数对字符串进行编码/解码,将字符的unicode编码转化为16进制序列。它也是可以解码中文的。用于服务端与服务端传输多。它不对/进行编码。

    <script>
      let uri = "https://www.davina/com/from=http://wwws.baidu.com";
      console.log(escape(uri)); //https%3A//www.davina/com/from%3Dhttp%3A//wwws.baidu.com
    </script>

  2. HSTS

    HTTP(Strict-Transport-Security)它是一个Web安全策略机制。HSTS的作用是强制客户端使用HTTPS与服务器创建连接。它是国际互联网工程组织IETF正在推行的一种新的安全协议。

  3. 缓存检查

  二、DNS解析

     NDS(Domain Name System): NDS服务它是一种提供域名到ip地址之间的解析服务。计算机即可以被赋予ip地址,也能被赋予主机名和域名。它解析有以下几步组成:

     1.当一个用户要地址栏中输入www.baidu.com时,DNS解析大致分为以下几步:

     查找本地是否有缓存,如果有则本地解析,本地解析的话浏览器先检查自身中有没有缓存,如果有,解析结束。如果没有,则 查看c盘hosts文件,如果有浏览器会首先使用这个ip地址。如果本地hosts文件里没有,则请求本地DNS解析器,解析这个过程。

     如果本地没有缓存,从根域名服务器,*域名服务器,权威域名服务器上进行查找,把查找到的结果返回给本地DNS解析器,返回给客户端。

URL解析过程

   三、建立TCP通道

    浏览器通过DNS获取到web服务器真的IP地址后,便向服务器发起TCP连接请求,通过TCP的三次握手建立好连接后,浏览器便可以将http请求数据通过发送给服务器了。那什么是TCP?为什么需要握手?为什么握手不是两次,或者是4次而是三次?

   TCP是可靠通信协议,接收方收到的是完整,有序,无差错的数据。可靠性高,应用于传输大量数据对可靠性要求高的场合。与TCP相对的是UDP它是不可靠通信协议,接收方接收到的数据可能存在部分的丢失,顺序也不一定能保证,但是它是的传输速度快。

   TCP和UDP协议它们都是基于同样的互联网基础设施,基于IP协议来实现的,互联网基础设施中对于数据包的发送过程是会发生丢包现象的而TCP协议为了实现可靠传输引入了序号(sequence number)

和确认号(acknowledgement number)确保了通信双方会判断自己发送的数据包对方是否收到,如果没有收到则重发,而UDP则做不到。

   发送方要发送数据包时,同时送一个序号,那么接收方收到这个数据包后,就可以回复一个确认号,告诉发送方“我已经收到了你的数据包,你可以发送下一个数据包,序号从某某开始”。

   为什么是三次而不是两次?是因为为了实现可靠传输,发送方和接收方始终需要同步序列编号(Synchronize Sequence Numbers)。 需要注意的是, 序号并不是从 0 开始的, 而是由发送方随机选择的

初始序列号 ( Initial Sequence Number, ISN )开始 。 由于 TCP 是一个双向通信协议, 通信双方都有能力发送信息, 并接收响应。 因此, 通信双方都需要随机产生一个初始的序列号, 并且把这个起始值告诉对方。

   所以TCP的三次握手如下:

    第一次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入SYN_SENT(Synchronize Sequence Numbers)状态,等待服务器确认;

    第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;

    第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

URL解析过程

  四、发送HTTP请求,服务期处理请求,返回响应结果

    在了解如何发送HTTP请求时,我们要知道什么是HTTP协议?HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,它基于TCP/IP通信协议来传递数据,浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。

    如果说HTTP是因特网的信使,那么HTTP报文就是它用来搬东西的包裹了。HTTP报文是在HTTP应用程序之间发送的简单的格式化数据块,每条报文都包含一条来自客户端的请求,或者一条来自服务器的响应

    一个HTTP请求报文由请求行(request line)、请求头部(header)、空行和请求数据4个部分组成。

  1. 请求行

  定义:它是请求报文的起始行,包含了一个方法和一个请求URL,这个方法描述了服务器应该执行的操作,请求URL描述了要对哪个资源执行这个方法。请求行中还包含HTTP的版本,用来告知服务器,客户端使用的是哪种HTTP。所有这些字段都由空格符分隔。

  请求行:请求行分为三个部分:请求方法、请求地址URL和HTTP协议版本,它们之间用空格分割

   请求方法:请求的起始行以方法作为开始,方法用来告诉服务器要做什么,常见的请求方法有以下几种:GET系列:GET / DELETE / HEAD / OPTIONS,POST系列:POST / PUT 下面分别进行介绍:

  GET系列 : 一般认为是从服务器获取到信息,当然也可以把客户端的信息传递给服务器,给的少,拿的多。

    GET: GET是最常用的方法。通常用于请求服务器发送某个资源。GET方法要求服务器将URL定位的资源放在响应报文的数据部分,发送给客户端。使用GET方法时,请求参数和对应的值附加在URL后面,利用问号‘?’代表URL的结尾与请求参数的开始,传递参数长度受限制。

    DELETE: DELETE方法所做的事情就是请服务器删除请求URL所指定的资源。一般应用于想删除服务器上的文件或者是一些大量的信息。

    HEAD: 只需要获取响应头的信息就可,响应主体信息不接受。这就允许客户端在未获取实际资源的情况下,对资源的首部进行检査。

    OPTIONS: 试探性请求,这个请求用于校验客户端和服务器端是否正常连接。

  POST系列:一般认为是给服务器推送信息,给的多,拿的少。

    POST: POST方法将请求参数封装在HTTP请求数据中,以名称/值的形式出现,可以传输大量数据,这样POST方式对传送的数据大小没有限制,而且也不会显示在URL中.POST方式大多用于页面的表单中.

    PUT: PUT方法会向服务器写入文档。一般用于给服务器传递文件或者是大的数控,如文本编辑器编辑的内容。

  GET与POST的区别:

    GET传递的服务器的信息一般都是基于url地址问号传参来进行实现,如:./data.json?x=1&name=davina&xxx=xxx......。地址中‘?’之后的部分就是通过GET发送的请求数据,各个数据之间用‘&’符号隔开。

    不足:GET方式不适合传送私密数据。不同浏览器对地址字符的限制也不尽相同。一般最多只能识别1024个字符,所以如果需要传送大量数据的时候,也不适合使用GET方式。

    POST: 允许客户端给服务器提供信息较多,POST传递给服务器的信息一般基于请求主体来实现,客户端还可以基于设置请求头,把一些简要的信息传递给服务器。

    区别:

    GET传递给服务器的信息小于POST.因为不同浏览器对地址字符的限制也不尽相同。一般最多只能识别1024个字符,超出浏览器限制的部分,内容会被自动裁切掉,POST请求理论上是没有长度的限制(请求主体没有设置大小限制),但在真实的项目中为了保证数据传输的高效性,我们一般都会手动做限制。

    安全问题:POST相对GET安全一些,项目中涉及安全信息的传输都是要用POST。主要原因是:get基于url传数据,但容易被url劫持掉,这样不安全,post相对来说安全,但也不是绝对的安全。所以对于重要信息的传输也需要进行手动的加密处理。

    缓存问题:浏览器会在处理GET请求时,如果两次请求的地址后面参数一致,浏览器会自己设置数据缓存(当然这个缓存我们不想要)想要不走浏览器的缓存,我们需要保证每次请求的url都不完全一致:每次请求,问号传参后加上随机数或者时间戳‘如:‘./data.json?x=1&name=davina&_=‘+Math.random()。

  状态码:HTTP状态码负责表示客户端HTTP请求的返回结果、标记服务器端的处理是否正常、通知出现的错误等工作。HTTP状态码被分成了五大类,不同的类型代表不同类别的状态码。

  【1XX】: Informational(信息性状态码) 表示接收的请求正在处理

  【2XX】:Success(成功状态码) 表示请求正常处理完毕

       【3XX】:Redirection(重定向状态码) 表示需要进行附加操作以完成请求

  【4XX】 :Client Error(客户端错误状态码) 表示服务器无法处理请求

  【5XX】 :Server Error(服务器错误状态码) 表示服务器处理请求出错

  2. 请求头部 

    请求头部为请求报文添加了附加的信息,它是HTTP报文的要素之一。HTTP首部字段是由首部字段名和字段值构成(名/值),中间用冒号“:” 分隔。每行一对,名和值之间使用冒号分隔。请求头部的最后会有一个空行,表示请求头部结束,接下来为请求数据。它可以分为五类:通用首部、请求首部、响应首部、实体首部和扩展首部。

    通用首部:通用首部可以在客户端、服务器和其他应用程序之间提供一些非常有用的通用功能,下面是一些常见的通用首部信息:

    首部:Connection  描述:允许客户端和服务器指定与请求/响应连接有关的选项,如Connection:Keep-Alive

    首部:Date`  描述:提供日期和时间标志,说明报文是什么时间创建的

    首部:MIME-Version  描述:给出了发送端使用的MIME版本

  请求首部:只在请求报文中有意义的首部。用于说明是谁或什么在发送请求、请求源自何处等等信息。常见的有以下:

    首部:From  描述:提供了客端用户的地址

    首部:Host  描述:给出了接收请求的服务器的主机号和端口名

    首部:User-Agent  描述:将发起请求的应用程序名称告知服务器

  响应首部:响应报文有自己的响应首部集。响应首部为客户端提供了一些额外信息

  实体首部:实体首部提供了有关实体及其内容的大量信息,实体首部可以告知报文的接收者它在对什么进行处理。

  扩展首部:HTTP首部字段是可以自行扩展的。所以在Web服务器和浏览器的应用上,会出现各种非标准的首部字段。    

  五、关闭TCP连接通道(四次挥手)

  第一次挥手: 首先从客户端开始发出连接释放报文,并且停止发送数据,这客户端进入到终止等待1状态。

  第二次挥手:从服务器到客户端 。服务器收到连接释放报文,发出确认报文且带上自己的序列号,这时服务器端进入了关闭等待状态。

        这时TCP服务器要通知高层的应用进程,客户端向服务器释放,这时服务器处于半关闭状态。如果服务器还有数据要发送,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

        客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据

  第三次挥手:服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,由于在半关闭状态,服务器很可能又发送了一些数据,服务器就进入了最后确认状态,等待客户端的确认。

  第四次挥手:客户端收到服务器释放报文后,发出确认此时,客户端就进入了时间等待状态。因为此时TCP连接还没有释放,必须经过一段时间2∗∗MSL(最长报文段寿命),因为网络是不可靠的,有可以最后一个ACK丢失。所以时间状态就是用来重发可能丢失的ACK报文的。当客户端撤销相应的TCB后,才进入CLOSED状态。
        服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。服务器结束TCP连接的时间要比客户端早一些。

  所以我们可以看到当服务器端收到客户端的SYN连接请求报文后,可以直接的发送请求连接和确认连接,但在关闭的时候,服务器收么到关闭信息后,很可能不会立即关闭,它需要时间来反应,只能先回复一个确认,只有当服务器端所有的报文都发送完后,服务器端才能发送希望断开连接。所以需要挥手需要四步来完成。

URL解析过程

  六、客户端渲染

  不同的浏览器内核不同,所以渲染过程不太一样。但大体上浏览器渲染进程包含解析HTML文件和CSS文件、加载图片资源文件,执行解析js文件脚本代码等待内容。整个过程浏览器会开启多个线程协作完成。

URL解析过程

上一篇:aspnetcore配置log4net并添加全局异常处理


下一篇:Electron中实现通过webview实现内嵌网页并嵌入css样式和js脚本等