浅谈从输入 URL 到页面展现发生了什么

136 阅读26分钟

从输入 URL 到页面展现发生了什么

  1. 解析 URL。
  2. 缓存判断。
  3. 域名解析 (DNS 解析)。
  4. 获取 MAC 地址。
  5. TCP 三次握手。
  6. HTTPS 的 TLS 四次握手
  7. 发送 HTTP 请求。
  8. 服务器处理请求并返回 HTTP 报文。
  9. 断开连接。
  10. 浏览器解析渲染页面。

解析 URL

分析 URL 所需要使用的传输协议和请求的资源路径。如果输入的 URL 中的协议或者主机名不合法,将会把地址栏中输入的内容传递给搜索引擎。如果没有问题,浏览器会检查 URL 中是否出现了非法字符,则对非法字符进行转义后在进行下一过程。

URL 由哪些组成部分

以下面的URL为例:www.learnTest.com:8080/news/index.…

从上面的URL可以看出,一个完整的URL包括以下几部分:

  • 协议部分: 该URL的协议部分为“http:”,这代表网页使用的是HTTP协议。在Internet中可以使用多种协议,如HTTP,FTP等等本例中使用的是HTTP协议。在"HTTP"后面的“//”为分隔符;
  • 域名部分: 该URL的域名部分为“www.learnTest.com”。一个URL中,也可以使用IP地址作为域名使用
  • 端口部分: 跟在域名后面的是端口,域名和端口之间使用“:”作为分隔符。端口不是一个URL必须的部分,如果省略端口部分,将采用默认端口(HTTP协议默认端口是80,HTTPS协议默认端口是443);
  • 虚拟目录部分: 从域名后的第一个“/”开始到最后一个“/”为止,是虚拟目录部分。虚拟目录也不是一个URL必须的部分。本例中的虚拟目录是“/news/”;
  • 文件名部分: 从域名后的最后一个“/”开始到“?”为止,是文件名部分,如果没有“?”,则是从域名后的最后一个“/”开始到“#”为止,是文件部分,如果没有“?”和“#”,那么从域名后的最后一个“/”开始到结束,都是文件名部分。本例中的文件名是“index.html”。文件名部分也不是一个URL必须的部分,如果省略该部分,则使用默认的文件名;
  • 锚部分: 从“#”开始到最后,都是锚部分。本例中的锚部分是“name”。锚部分也不是一个URL必须的部分;
  • 参数部分: 从“?”开始到“#”为止之间的部分为参数部分,又称搜索部分、查询部分。本例中的参数部分为“testID=5&ID=123456&page=1”。参数可以允许有多个参数,参数与参数之间用“&”作为分隔符。

缓存判断

浏览器会判断所请求的资源是否在缓存里,如果请求的资源在缓存里且没有失效,那么就直接使用,否则向服务器发起新的请求。

DNS 解析

DNS 是什么

域名系统(英文:Domain Name System,缩写:DNS)是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。通俗点说就是把域名映射为 IP 的系统,访问的时候可以直接访问域名,更方便一些。

MDN: developer.mozilla.org/zh-CN/docs/…

层次化域名空间

  1. 根域名

    在我们输入网址 www.xxxx.com 的时候浏览器实际访问的是 www.xxxx.com. 最后会有一个 '.',这个点就是根域。

  2. 顶级域名(一级域名)

    网址 www.xxxx.com 中的 .com 就是顶级域名。例如: .cn.org.edu 等这些都是顶级域名。

  3. 二级域名

    网址 www.xxxx.com 中的 xxxx.com 就是二级域名。例如: .com.cn.net.cn.edu.cn 等。

  4. 三级域名

    网址 www.xxxx.com 就是一个三级域名。

DNS 服务器

  1. 本地域名服务器(LDNS)

    每个电脑都预置了本地 DNS 服务器(简称 LDNS),当访问域名的时候就会向本地 DNS服务器发送请求,最终通过权威域名服务器得到答案。

  2. 权威域名服务器(权威 DNS)

    负责对请求做出权威的回答。

    权威域名服务器会有三种返回结果:

    • A 记录: 记录着某域名和其 IP 的映射。
    • NS 记录: 记录着某域名和负责解析该域名的权威域名服务器。
    • CNAME 记录: 记录着某域名及其别名。

    当有请求来询问域名,权威域名服务器负责告诉 LDNS 对应 IP(A 记录);如果是需要其他权威域名服务器回答的,则告诉 LDNS 可能知道该域名对应 IP 的权威域名服务器(NS 记录);如果该域名是一个别名类型的就告诉 LDNS CNAME(CNAME 记录),LDNS 再去解析别名。

  3. 根域名服务器(根 DNS)

    当 LDNS 啥都不知道,没有任何结果的时候(没有任何缓存)就会来问根域名服务器,它可以告诉 LDNS 下一步该去问谁。

DNS 的解析过程

没有缓存时的解析过程

www.learndns.com 为例:

  1. 在浏览器中输入 www.learndns.com询问本地域名服务器: www.learndns.com 的 IP 是什么。
  2. 本地域名服务器不知道其对应 IP,则会询问根域名服务器: .(根域名服务器) 的 IP 是什么。
  3. 根域名服务器答复: 我也不知道,但是 .com 域名服务器有可能知道,你可以去问问它。
  4. 本地域名服务器向 .com 域名服务器询问: www.learndns.com 的 IP 是什么。
  5. .com 域名服务器答复: 我也不知道,但是 learndns.com 域名服务器有可能知道,你可以去问问它。
  6. 本地域名服务器向 learndns.com 域名服务器询问: www.learndns.com 的 IP 是什么。
  7. learndns.com 域名服务器答复: 对应的 IP 或者 别名为 1.1.1.1
  8. 如果本地域名服务器得到的是一个别名,则还需要对别名进行查询。
  9. 本地域名服务器到 IP 之后本地域名服务器做两件事情:
    1. 将 IP 返回给浏览器。
    2. 将 IP 放到缓存中。

引用图片

2021090913454143.jpg

有缓存时的解析过程

在有缓存的时候,任意一步中有缓存则都会直接将缓存结果返回。

依然以 www.learndns.com 为例:

  1. 在浏览器中输入 www.learndns.com浏览器会先查看自身有没有对这个域名的缓存,有则返回。
  2. 浏览器中没有缓存再去问操作系统缓存中是否有对这个域名的缓存,有则返回。
  3. 操作系统中没有缓存则再去 hosts 文件中查找,有则返回。
  4. hosts 文件中也没有时才会再去问本地域名服务器
  5. 本地域名服务器会先看自身有没有 www.learndns.com 对应 IP,也就是权威域名服务器中的 A 记录,有则返回。
  6. 本地域名服务器中没有则再去问 learndns.com 域名服务器有没有 NS 记录,有则去问它。
  7. 上述都没有则再去问顶级域名服务器 .com 域名服务器中有没有 NS 记录,
  8. 如果顶级域名服务器中也没有 NS 记录才会去问根域名服务器。

只有在 1 - 7 中都没有缓存的时候才会去问根域名服务器

递归 DNS

通常就是 LDNS,它接收终端的域名查询请求,负责在网上问一圈之后将最终 IP 返回终端。

参考链接

dns域名系统的作用是什么(dns域名解析过程)

一文彻底搞定DNS面试题

获取 MAC 地址

当浏览器得到 IP 地址后,数据传输还需要知道目的主机 MAC 地址,因为应用层下发数据给传输层,TCP 协议会指定源端口号和目的端口号,然后下发给网络层。网络层会将本机地址作为源地址,获取的 IP 地址作为目的地址。然后将下发给数据链路层,数据链路层的发送需要加入通信双方的 MAC 地址,本机的 MAC 地址作为源 MAC 地址,目的 MAC 地址需要分情况处理。通过将 IP 地址与本机的子网掩码相结合,可以判断是否与请求主机在同一个子网里,如果在同一个子网里,可以使用 APR 协议获取到目的主机的 MAC 地址,如果不在一个子网里,那么请求应该转发给网关,由它代为转发,此时同样可以通过 ARP 协议来获取网关的 MAC 地址,此时目的主机的 MAC 地址应该为网关的地址。

TCP 三次握手

重要字段

  • seq(sequence number): 序列号/顺序号;用来表示 TCP 发起端向接收端发送的字节流,发起端发送数据时对此进行标记。(可以理解为发送自己的数据)
  • ack(acknowledgement number): 确认号;只有 ACK 标志位存在时,确认号字段才有效。(可以理解为发送接收到的数据)
  • 标志位(flags): 共 6 个,即 URG、ACK、PSH、RST、SYN、FIN 等。具体含义如下:
    • URG: 紧急指针(urgent pointer)有效。
    • ACK: 确认号有效。(为了与确认号 ack 区分开,这里采用大写,可以理解为用于确定收到了请求)。
    • PSH: 接收方应该尽快将这个报文交给应用层。
    • RST: 重置连接。
    • SYN: 发起一个新连接。
    • FIN: 释放一个连接。

作用

  • seq(序号)、ack(确认号): 用于确认数据是否准确,通信是否正常。
  • 标志位: 用于确认/更改连接状态。

详情

image

第一次握手

由浏览器发起,询问服务器我可以和你建立连接吗,可以接收到我的数据吗?

客户端发送一个标志位 SYN、序列号 seq = x 的数据包。发送完成后,客户端进入 SYN_SEND 状态(链接发送状态)。

  • 标志位 SYN 表示要建立连接。(我可以和你建立连接吗)
  • 序列号 seq = x 表示向接收端发送的数据。(可以接收到我的数据吗)

第二次握手

由服务端发起,服务端答应可以建立连接,已收到你的连接请求,能收到我的数据吗?你这数据是这个吗?

服务端发送一个标志位 SYN、标志位 ACK、序列号 seq = y 和 确认号 ack = x + 1 的数据包。发送完成后服务端进入 SYN_RCVD 状态(连接收到状态)。

  • 标志位 SYN 表示要建立连接。(可以建立连接)
  • 标志位ACK 表示收到了请求。(已收到你的连接请求)
  • 序列号 seq = y 表示向接收端发送的数据。(能收到我的数据吗)
  • 确认号 ack = x + 1 表示上一次握手发来的序列号 seq 的值 + 1。(你这数据是这个吗)

第三次握手

由客户端发起,客户端应答已收到你的回复,这是我的数据,这是你的数据。我马上就要发送请求了,准备接收吧。

客户端发送一个标志位为 ACK、确认号 ack = y + 1 和序列号 seq = x + 1 的数据包。

  • 标志位 ACK 表示收到请求。(已收到你的回复)
  • 序列号 seq = x + 1 表示上一次握手发来的 ack 的值。(这是我的数据)
  • 确认号 ack = y + 1表示上一次握手发来的序列号 seq 的值 + 1。(这是你的数据)

将双方的数据发送用于再次验证核对

问题

为什么需要三次握手,而不是两次或者四次?

《计算机网络》中提到目的是为了防止已经失效的连接请求报文段突然又传到服务器,因而产生错误。

场景:

客户端第一次握手发出去的第一个连接请求报文并没有丢失,而是因为某些未知的原因在某个网络节点上发生滞留,导致发生延迟,一直到 socket 连接释放以后的某个时间节点第一次握手的连接请求报文才到达服务端。本来这是一个早已失效的报文段,但是服务端收到此失效的报文后,会误认为是客户端再次发出的一个新的连接请求,于是服务端就向客户端发出确认报文,表示同意建立连接。

  1. 为什么不是两次握手?

    如果不采用三次握手,那么只要服务端发出确认报文(第二次握手)就会认为新的连接已经建立,但是客户端并没有发出建立连接的请求,因此不会向服务端发送数据,服务端没有收到数据就会一直等待,这样服务端就会浪费掉很多资源。如果采用三次握手的话就不会出现这种情况,服务端收到一个过时失效的报文段后,向客户端发出确认报文,此时客户端并没有要求建立连接,所以就不会向服务端发送确认连接的请求,这个时候服务端也能知道连接没有建立。

  2. 为什么不是四次握手?

    因为通过前三次已经建立了一个可靠的连接,如果再发送第四次确认消息的话,则会浪费资源。

需要三次握手的本质

信道传输是不可靠的,但是我们要建立可靠的连接并且发送可靠的数据,也就是数据传输是需要可靠的。在这个时候三次握手是理论上的最小值。三次握手并不是说是 TCP 协议要求的,而是为了满足在不可靠的信道上传输可靠的数据所要求的。

为什么第三次握手没有发送标志符为 SYN 的包?

个人理解标志符为 SYN 的包是来要求接收方要以一个新的连接来应答自己,而第三次握手是不需要应答的,所以没有发送标志符为 SYN 的包。

参考链接

从 URL 输入到页面展现到底发送什么

面试必备HTTP之TCP三次握手及四次挥手详解

TCP的三次握手各字段(ack,seq,ACK,SYN)是什么意思?

tcp建立连接为什么需要三次握手

HTTPS 的 TLS 四次握手

如果使用的是 HTTPS 协议,在通信前还存在 TLS 的四次握手

  1. 首先由客户端向服务器端发送 TLS 协议的版本号、一个随机字符串和支持使用的加密算法。
  2. 服务器端收到后,确认加密的算法,也向客户端发送一个随机字符串、确定的加密算法和自己的数字证书(包含公钥)。
  3. 客户端收到后,首先检查数字证书是否有效,如果有效,则再生成一个随机字符串,并使用证书中的公钥对随机字符串加密,再生成一个前面所有内容的 hash 值供服务器端检验,然后发送给服务器端。
  4. 服务器端接收后,使用自己的私钥对数据解密,同时向客户端发送一个前面所有内容的 hash 值供客户端检验。
  5. 这个时候双方都有了三个随机字符串,按照之前所约定的加密方法,使用这三个随机字符串生成一把共享秘钥。以后双方通信前,就使用这个秘钥对数据进行加密后再传输。

TLS 四次握手.png

全程采用的加密方式:

  1. 客户端使用非对称加密与服务器进行通信,实现身份的验证并协商对称加密使用的秘钥。
  2. 通过散列函数 hash 来校验数据完整性。
  3. 数据通信时采用对称加密,不同节点之间采用的对称秘钥不同,从而保证信息只能通信双方获取。

优点

  1. 使用 HTTPS 协议可以认证用户和服务器,确保数据发送到正确的客户端和服务器。
  2. 使用 HTTPS 协议可以进行加密传输、身份认证,通信更加安全,防止数据在传输过程中被窃取、修改,增加数据安全性。
  3. HTTPS 是目前最安全的解决方案,虽然不是绝对的安全,但是大幅增加了中间人攻击的成本。

缺点

  1. HTTPS 协议需要服务器和客户端双方的加密和解密处理,耗费资源更多、过程复杂。
  2. HTTPS 协议握手阶段比较费时,增加页面的加载时间。
  3. SSL 证书是收费的,功能越强大的证书费用越高。
  4. SSL 证书需要绑定 IP,不能在同一个 IP 上绑定多个域名。

HTTPS 是如何保证安全的

先理解两个概念:

  1. 对称加密: 即通信的双方都使用同一个秘钥进行加解密,对称加密虽然很简单性能也好,但是无法解决首次把秘钥发给对方的问题,很容易被黑客拦截秘钥。

  2. 非对称加密:

    • 私钥 + 公钥 = 秘钥对。
    • 用私钥加密的数据,只有对应的公钥才能解密,用公钥加密的数据,只有对应的私钥才能解密。
    • 因为通信双方的手里都有一套自己的秘钥对,通信之前双方会把自己的公钥都先发给对方。
    • 然后对方再拿着这个公钥来加密数据响应给对方,数据到了对方那里,对方再用自己的私钥进行解密。

    非对称加密虽然安全性高,但是带来的问题就是速度很慢,影响性能

    解决办法:

    结合两种加密方式,将对称加密的秘钥通过非对称加密的公钥加密,然后发送出去,接收方使用公钥进行解密得到对称加密的秘钥,然后双方可以使用对称加密进行沟通。

    此时又带来了一个问题,中间人问题:

    如果此时在客户端和服务器之间存在一个中间人,这个中间人只需要把原本双方通信互发的公钥,换成自己的公钥,这样中间人就可以轻松解密通信双方发送的所有数据。

    解决办法:

    这个时候需要一个安全的第三方颁发证书(CA)来证明身份,防止被中间人攻击,证书中包括: 签发者、证书用途、使用者公钥、使用者私钥、使用功能这的 hash 算法、证书到期时间等。

    但是问题又来了: 如果中间人篡改了证书,那么身份证明不就无效了?这个证书就白买了

    解决办法:

    通过数字签名来解决这个问题,数字签名是用 CA 自带的 hash 算法对证书的内容进行 hash,得到一个摘要,再用 CA 的私钥加密,最终组成数字签名。当别人把它的证书发过来的时候,我再用同样的 hash 算法再次生成消息摘要,然后用 CA 的公钥对数字签名进行解密,得到 CA 创建的消息摘要,两者一比,就知道中间有没有被人篡改,这个时候就最大程度保证了通信的安全。

发送 HTTP 请求

请求报文

请求报文由请求行、请求头、空行和请求体四个部分组成。

image

POST /getUser?id=ID HTTP/1.1
HOST: www.XXX.com
User-Agent: Mozilla/5.0(Windows NT 6.1;rv:15.0) Firefox/15.0

name=test&age=12

请求行

请求行包含请求方法、URL 和版本协议。

POST /getUser?id=ID HTTP/1.1
  • 请求方法包括 GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS 和 TRACE。

  • URL 即请求地址,由协议(protocol)://主机(host):端口(port)/路径?参数组成。

    https://www.user.com:7001/getUser?id=123

  • 协议版本即 HTTP 版本号

请求头

请求头包含该请求的附加信息,由 key: value 组成,每个请求头独立成行。

HOST: www.XXX.com
User-Agent: Mozilla/5.0(Windows NT 6.1;rv:15.0) Firefox/15.0

请求体

请求体可以承载多个请求参数,但是并不是所有请求都会有请求体。

name=test&age=12 // 有 name 和 age 两个参数

服务器处理并返回 HTTP 报文

响应报文

响应报文由响应行、响应头部、空行和响应主体三部分组成。

image

HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Document</title>
</head>
<body>
    <p>this is http response</p>
</body>
</html>

响应行

响应行包含协议版本、状态码以及状态码描述

HTTP/1.1 200 OK

状态码规则:

  • 1xx: 指示信息,表示请求已接收,继续处理。
  • 2xx: 成功,表示请求已被成功接收、理解、接受。
    1. 204 表示客户端发送的请求已经在服务端正常处理了,但是没有返回内容。一般情况在只需要从客户端往服务端发送信息,而服务器不需要往客户端发送内容时使用。
  • 3xx: 重定向,要完成请求必须进行更进一步的操作。
    1. 301 永久重定向,在收藏夹中是可以看到网址变化,下次访问的就是新地址

      使用场景: 不再使用旧域名时使用。

    2. 302 临时重定向,在收藏夹中显示的还是旧地址,下次访问的还是原地址

      使用场景: 做活动页时,登录到首页自动重定向;未登录得到用户访问到其他页面需要登录才能访问的页面时,重定向到登录页;访问 404 页面重定向到首页。

    3. 304 资源未被修改,已经被请求过一次了,服务端告诉客户端之前请求的资源还有效,可以直接使用本地缓存中的

    4. 307 表示临时重定向,该状态码和 302 有着相同含义,尽管 302 标准禁止 POST 变成 GET,但是实际使用时还是这样做了

      307 会遵守浏览器标准,不会从 POST 变成 GET,规范要求浏览器继续向 Location 的地址 POST 内容。

  • 4xx: 客户端错误,请求有语法错误或请求无法实现。
    1. 400 请求报文中存在语法错误。当错误发生时,需要修改请求的内容后再次发送请求。
    2. 404 资源未找到
    3. 403 没有权限
  • 5xx: 服务器端错误,服务器未能实现合法的请求。
    1. 500 服务器错误
    2. 504 网关超时

响应头

响应头包含该响应的附加信息,由 key: value 组成,每个响应头独立成行。

Content-Encoding: gzip
Content-Type: text/html;charset=utf-8

响应体

响应体包含了服务器返回给客户端的文本信息,并不是所有响应报文都有响应体。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Document</title>
</head>
<body>
    <p>this is http response</p>
</body>
</html>

断开连接

TCP 四次挥手

重要字段

  • seq(sequence number): 序列号/顺序号;占 32 位,用来表示 TCP 发起端向接收端发送的字节流,发起端发送数据时对此进行标记。(可以理解为发送自己的数据)
  • ack(acknowledgement number): 确认号;占 32 位,只有 ACK 标志位为 1 时,确认号字段才有效。(可以理解为发送接收到的数据)
  • 标志位(flags): 共 6 个,即 URG、ACK、PSH、RST、SYN、FIN 等。具体含义如下:
    • URG: 紧急指针(urgent pointer)有效。
    • ACK: 确认号有效。(为了与确认号 ack 区分开,这里采用大写,可以理解为用于确定收到了请求)。
    • PSH: 接收方应该尽快将这个报文交给应用层。
    • RST: 重置连接。
    • SYN: 发起一个新连接。
    • FIN: 释放一个连接。

作用

  • seq(序号)、ack(确认号): 用于确认数据是否准确,通信是否正常。
  • 标志位: 用于确认/更改连接状态。

详情

image

第一次挥手

由浏览器发起,客户端告诉服务器: 我已经不会再给你发送数据了。

用来关闭发送方到接收方的数据传送,发送完成之后客户端进入 FIN_WAIT_1 状态。也就是客户端告诉服务器: 我已经不会再给你发送数据了。但是在标志位为 FIN 的数据包之前发送出去的数据,如果没有收到对应的标志位为 ACK 的确认数据包,客户端依然会重发这些数据

  • 标志位 FIN 表示释放连接。
  • 标志位 ACK 表示收到了请求,应答上次连接。
  • FIN_WAIT_1 状态: 表示主动发送关闭连接请求后,在等待另一方的标志位为 FIN 的报文,发送完成之后进入该状态。

第二次挥手

由服务端发起,也就是告诉客户端: 请求已经收到,但是我还没有准备好,请继续等待我释放连接的消息。

服务端防止还有数据没有传输完成,所以并没有发送标志位为 FIN 的释放连接数据包,而是先发送了一个 ACK 确认收到的应答数据包。发送后,服务端进入 CLOSE_WAIT 状态。也就是告诉客户端: 请求已经收到,但是我还没有准备好,请继续等待我释放连接的消息。当客户端收到之后,客户端进入 FIN_WAIT_2 状态。

  • 标志位 ACK 表示收到了请求,应答上次连接。
  • CLOSE_WAIT 状态: 表示收到对方标志位为 FIN 的报文后,回给对方标志位为 ACK 的报文后的状态,等待关闭,看看自己是否还有数据要发送。
  • FIN_WAIT_2 状态: 收到另一方发送的标志位为 FIN 的报文后立即进入该状态,此时可能还会接收数据,等待另一方标志位为 FIN 的报文。

第三次挥手

由服务端发起,告诉客户端: 服务器这边数据传输完成,已经准备好关闭连接了。

服务端确认数据已经传输完成,则向客服端发送标志位为 FIN 和 ACK 的数据包,告诉客户端: 服务器这边数据传输完成,已经准备好关闭连接了。服务端发送之后进入 LAST_ACK 状态。

  • 标志位 FIN 表示释放连接。
  • 标志位 ACK 表示收到了请求,应答上次连接。
  • LAST_ACK 状态: 表示收到对方的发送的标志位为 FIN 的报文之后,回个对方标志位为 ACK 的报文,然后自己也要关闭发送标志位为 FIN 的报文后,等待另一方标志位为 ACK 的报文时的状态。

第四次挥手

由客户端发起,高度服务器: 我这边也准备好关闭连接了,你也可以关闭了。

客户端收到服务器发起的第三次挥手之后,已经知道可以关闭连接了,同时它需要应答服务端的最后一次确认,所以会向服务器发送标志位为 ACK 的数据包。发送成功后客户端进入 TIME_WAIT 状态。服务端收到后正式服务端正式断开连接,进入 CLOSED 状态。同时客户端在发送之后等待 2MSL 后依然没有收到回复则证明服务端已正常关闭,客户端随即也断开连接进入 CLOSED 状态。

  • 标志位 ACK 表示收到了请求,应答上次连接。
  • MSL(Max Segment Lifetime): 为一个 TCP 报文在 Internet 上的最长生存时间。2MSL 就是两个这样的时间。
  • CLOSED 状态: 表示连接已经断开。

问题

为什么需要四次挥手,三次不可以吗?

如果是三次挥手,即省略了第三次挥手,将第三次和第二次合并为一次,也就是在服务器收到客户端发送的关闭请求后,把SYN和ACK包一起发过去。这样会造成服务端和客户端之间还有数据没有传输完成,造成数据的丢失,所以中间的这段时间,等待服务器把剩余的数据传输完成是很有必要的。

参考链接

面试必备HTTP之TCP三次握手及四次挥手详解

tcp建立连接为什么需要三次握手

访问Web,tcp传输全过程(三次握手、请求、数据传输、四次挥手)

从输入页面地址到展示页面信息都发生了些什么?

拒绝八股文,透过实战理解TCP连接过程

浏览器解析渲染页面

浏览器拿到响应体之后开始解析并渲染页面,整理流程分为五个部分:

  1. 将 HTML 解析生成 DOM 树。
  2. 将 CSS 解析生成 CSS 规则(rules)树。
  3. 结合 DOM 树和 CSS 规则树生成渲染(render)树。
  4. 根据渲染树计算每个节点的信息(布局)。
  5. 根据计算后的信息绘制页面。

将 HTML 解析生成 DOM 树

  • 解析的过程是按照深度优先遍历的原则,即优先解析当前节点的所有子节点,再解析下一个兄弟节点。
  • 解析生成 DOM 树的过程中有两种情况:
    1. 遇到 script 标签会暂停 DOM 的解析,直到脚本加载、解析、执行完毕,才会继续 DOM 的解析;

      阻塞的原因: JS 有可能会修改 DOM 结构,如果继续解析,有可能 JS 中会将已解析的 DOM 进行修改,这个时候已解析的就是无效的了。

    2. 遇到请求外部资源(iconfont、image等)时,将进行异步请求,不会阻塞 DOM 的解析;但是如果请求的是一个 JS 文件,同样会阻塞 DOM 的解析。

将 CSS 解析生成 CSS 规则树

  • 解析生成 CSS 规则树时不会影响 JS 文件的加载,但是会影响 JS 文件的执行,JS 代码执行前浏览器必须保证 CSS 规则树已经生成完毕。
  • 浏览器在 CSS 规则树生成之前不会进行渲染。

结合 DOM 树和 CSS 规则树生成渲染(render)树

  • DOM 树和 CSS 规则树全部准备好之后,浏览器开始生成渲染树。

根据渲染树计算每个节点的信息(布局)

  • 通过渲染树中每个节点的信息,计算出每个节点的位置和尺寸。

根据计算后的信息绘制页面

  • 绘制阶段,
  • 重绘: 某个元素的背景颜色、文字颜色等一系列不影响元素周围或内部布局的属性变动,称之为重绘。
  • 回流/重排: 某个元素的尺寸发生了变化或其他会影响元素周围或内部的属性变动,则需要重新计算渲染树,重新渲染,这种情况称之为回流或重排。

参考链接

从URL输入到页面展现到底发生什么?

前端经典面试题: 从输入URL到页面加载发生了什么?