输入url到底发生了神马

114 阅读9分钟

笔者在准备面试过程中遇到这个问题,现在将这个问题的知识点进行整合分析,归纳完全知识点。

  1. 用户在浏览器中输入url,浏览器接收到url。

2.浏览器接收到这个url之后,会根据这个url会先查看缓存,如果有缓存且没有过期的话直接提供给客户端,完成页面渲染。 这个过程涉及到强缓存和协商缓存。

1、强缓存(本地缓存

1.1. 概念

不用跟服务器进行通信,直接使用本地缓存的资源

1.2. 相关header字段

  • expires ------ HTTP1.0使用的expires
    一个未来时间,代表资源的有效期,没有过期之前都使用当前资源。
  • cache-control------HTTP1.1及其之后使用cache-control
    max-age: 当值设为max-age=300时(即300s),则代表在这个请求正确返回时间(浏览器也会记录下来)的5分钟内再次加载资源,就会命中强缓存。
    no-cache:不使用本地缓存。向浏览器发送新鲜度校验请求
    no-store:禁止浏览器缓存数据,也禁止保存至临时文件中,每次都重新请求,
    pubilc:任何情况下都缓存(即使是HTTP认证的资源)
    private:只能被终端用户的浏览器缓存,不允许CDN等中间层缓存服务器对其进行缓存。

2、协商缓存

2.1、概念

首先,将所缓存资源的信息发送给服务器,
其次,让服务器判断资源是否已经更新了,

  • 若已更新,则返回更新后的资源;
  • 若没有更新,则返回304状态,告诉浏览器可直接使用本地缓存的资源,

整个过程至少与服务器通信一次

2.2、相关header字段

  • 响应头: Last-Modified
    请求头: If-Modified-Since ( 资源修改的时间 )
  1. 浏览器第一次发请求,服务器在返回的 respone 的 header 加上 Last-Modified, 表示资源的最后修改时间

  2. 再次请求资源,在 requset 的 header 加上 If-Modified-Since , 值就是上一次请求返回的 Last-Modified 值

  3. 服务器根据请求传过来的值判断资源是否有变化,没有则返回 304, 有变化就正常返回资源内容,更新 Last-Modified 的值

  4. 304 从缓存加载资源,否则直接从服务器加载资源

  • 响应头:Etag
    请求头:If-None-Match(标识符字符串)

    一个标识符字符串,表示文件唯一标识,只要文件内容改动,ETag就会重新计算。缓存流程和 Last-Modified 一样。

2.3、Last-Modified 与 Etag 的对比:

  • 如果我们打开文件但并没有修改其内容,Last-Modified 也会改变,而Etag则不会改变。
  • Last-Modified 的时间单位为秒,如果一秒内对文件进行了多次修改,那么由于其时间单位是秒,所以Last-Modified不会改变,最终浏览器还是会去读取缓存资源,而此时缓存的资源已经过时了。
  • Etag的优先级高于Last-Modified。

2.4、为什么协商缓存有两个属性一起出现

协商缓存是浏览器判断资源是否可用,所以需要两个标识,

第一个是第一次请求的响应头带上某个字段(Last-Modified或者Etag),

第二个则是后续请求带上的对应请求字段(If-Modified-Since或者If-None-Match),

两个标识一起出现才有意义,单独则没有什么效果。

3、浏览器缓存过程(强缓存转协商缓存的过程)

  • 1.浏览器第一次加载资源,服务器返回200,浏览器将资源文件从服务器上请求下载下来,并把文件、文件的返回时间、response header一并缓存
  • 2.下一次加载资源时,查看cache-control的设置
    • 如果值是no-cache,则表示不缓存,则直接去请求数据;
    • 如果值是max-age,则比较当前时间和上一次返回200时的时间差是否大于max-age,若小于max-age,则表示没有过期,命中强缓存,不发请求直接从本地缓存读取该文件;如果时间差大于max-age,则表示资源过期了,则向服务器发送请求,并且header中携带有If-None-Match、If-Modified-Since、Etag值等
    • 3.如果服务器收到的请求头中,有Etag值优先根据Etag的值判断被请求的文件有没有做修改,
      如果Etag值一致则没有修改,命中协商缓存返回304,则读取缓存资源;
      如果Etag值不一致则有改动,则直接返回新的资源,并带上新的Etag值;
  • 4.如果服务器收到的请求头中,没有Etag值,则将If-Modified-Since被请求文件的最后修改时间做比对,
    如果一致则没有修改,命中协商缓存,返回304;
    如果不一致则有修改,则返回新的文件和并在响应头中携带last-modified ,下次请求时通过If-Modified-Since携带上last-modified的值;

3.否则浏览器就会通过DNS解析url ,获得协议名、主机名、端口号。

DNS解析详解:

  • 输入域名时,操作系统会先检查自己本地host文件中是否有这个网址的映射关系,如果有,就调用这个IP地址映射,完成域名解析。

  • 如果host没有这个域名的映射,则查找本地的DNS解析器缓存,是否有这个网址映射关系,如果有,直接返回,完成域名解析。

  • 如果本地解析器缓存没有的话,则查找本地DNS服务器,如果要查询的域名包含在本地配置资源中,则完成域名解析。

  • 如果本地DNS服务器没有的话,就会请求根服务器,根服务器就会返回一个负责该区域的主服务器IP

  • 本地域名服务器根据主服务器IP,链接到这个主域名服务器,如果有这个域名的话,就调用这个IP地址映射,完成域名解析。如果没有的话,则递归请求下一级域名服务器,直到找到对应的域名

4.然后浏览器就会根据这个IP跟对应的服务端建立tcp连接 TCP三次握手:

第一次握手:客户端向服务器发送一个 SYN=1 报文,并指定客户端的初始化序列号 seq=x。此时客户端处于SYN_Sent 状态

第二次握手:服务器接收到客户端的 SYN=1 报文后,同意连接的话,会发出一段确定报文。确定报文中应该ACK= 1,SYN= 1,确认号是ack=x+1,同时也要为自己初始化一个序列号seq=y.此时服务器处于 SYN-RCVD

第三次握手:客户端接收到 SYN 报文之后,还会向服务器发送确定。确定报文的 ACK=1,ack=y+1 ,自己的序列号变成 x+1。TCP 连接建立,客户端处于 已连接状态 。 image.png 5.当服务器接受到客户端的确认后也进入了 已连接状态 。此时双方就可以开始通信了

6.接下来就是浏览器向服务器发送HTTP请求 TCP 连接建立之后,浏览器端会构建请求行、 请求头等信息,并把和该域名相关的 Cookie 等数据附加到请求头中,然后向服务器发送构建的请求信息。如果是 HTTPS,还需要进行 TSL 协商。服务器还会检查 HTTP 的请求头,看是否包含缓存信息。

7.服务器接受并解析这个请求然后发送一个数据包给浏览器

8.关闭浏览器与服务器之间的连接 TCP四次挥手:

  • 第一次挥手:客户端向服务端发送一个FIN报文,报文中指定一个序列号。此时,客户端处于 FIN_WAIT-1状态

  • 第二次挥手:服务端收到客户端 发送的 FIN报文后,会将客户端的序列号+1 作为ACK报文的序列号值发送给客户端,表明收到了客户端的报文。然后服务器就会处于 CLOSE-WAIT-1状态

  • 第三次挥手:服务端向客户端发送 FIN报文,且指定一个序列号。此时,服务端处于 LAST_ACK状态

  • 第四次挥手:客户端收到服务端发送的FIN报文后,会将服务端的序列号+1 作为ACK报文的序列号值发送给服务端,此时客户端处于 TIME_WAIT 状态。需要等服务端确定收到自己的ACK报文后才会进入 CLOSED 状态 服务端接收到 ACK报文后,就关闭连接,处于 CLOSED 状态。 9.浏览器就会根据这个数据包解析HTML文档,构建DOM树,构建CSSOM树,解析js脚本,下载资源 渲染的具体过程:

  • 浏览器会通过 HTML Parser (HTML解析器)根据深度遍历的原则,将html解析成 DOM tree (DOM 树)。

  • 浏览器会通过 CSS Parser (CSS解析器)将CSS 解析成 CSS Rule Tree(CSSOM 树)。

  • 浏览器会将 javascript 通过 DOM API 或者 CSSOM API 将 JS代码进行解析并应用到布局中,且会呈现出响应式的结果。

  • 根据 DOM 树 与 CSSOM 树构建出响应的 render Tree。

  • 接下来就是进行重排(reflow)与重绘(repaint)。当页面中任意一个节点的几何尺寸发生变化的时候,就会触发重排,就会重新计算页面中所有的节点的位置。当页面中任意元素的样式属性发生变化时(几何尺寸不发生变化),就会发生重绘,重新绘画发生变化的元素。重排一定会触发重绘,而重绘不一定会有重排。

  • paint:绘制。遍历render Tree,并调用硬件图形API 来绘制每个节点到页面上。

10.最终就会显示出这个页面

总的来说分为以下几步

1. 用户在浏览器中输入url,浏览器接收到url。

2.浏览器接收到这个url之后,会根据这个url会先查看缓存,如果有缓存且没有过期的话直接提供给客户端,完成页面渲染。

3.否则浏览器就会通过DNS解析url ,获得协议名、主机名、端口号。

4.然后浏览器就会根据这个IP跟对应的服务端建立tcp连接

5.当服务器接受到客户端的确认后也进入了 已连接状态 。此时双方就可以开始通信了

6.接下来就是浏览器向服务器发送HTTP请求

7.服务器接受并解析这个请求然后发送一个数据包给浏览器

8.关闭浏览器与服务器之间的连接

9.浏览器就会根据这个数据包解析HTML文档,构建DOM树,构建CSSOM树,解析js脚本,下载资源

10.最终就会显示出这个页面