从输入 URL 到页面展示在浏览器中,发生了什么?

6dianbiqi Lv2

从输入 URL 到页面展示在浏览器中,中间都经历了啥?

1️⃣ URL 地址解析

首先我们拿到输入的 URL,对其进行解析,例如:

image

URL 解析,主要是解析出下面这些信息:

  • 【传输协议】:负责客户端和服务器端之间信息的传输(可以理解为快递小哥)。

    传输协议有以下几类:

    • http:即 HyperText Transfer Protocol,超文本传输协议。除传输文本内容外,还可传输图片和音视频等。
    • https:即 Hypertext Transfer Protocol Secure,HTTP+SSL,更安全的传输协议,经过加密处理。
    • ftp:即 File Transfer Protocol,文件传输协议,主要用于往服务器上上传内容和下载内容。
  • 【域名】:用于标识服务器在网络中的位置。

  • 【端口号】:

    端口号的作用是区分相同服务器上部署的不同项目,取值范围在 0 ~ 65535 之间。浏览器有默认端口号机制,我们在地址栏中输入 URL 地址,如果没有写端口号,则浏览器会根据当前的传输协议,自动把端口号加上!

    • http -> 80
    • https -> 443
    • ftp -> 21
  • 【请求资源的路径名称】。

  • 【问号传参信息】。

  • 【哈希值】:

    • Hash 值。

❗这里要注意 URL、URI、URN 的区别:

  • URL:统一资源定位符,用于定位资源
  • URI:统一资源标识符,用于标识资源
  • URN:统一资源名称,用于标识资源

它们之间的关系如下图所示:

image

2️⃣ 浏览器缓存检查

在输入 URL 到页面展示的过程中,我们需要加载许多资源,例如:

  • 一些静态资源,例如:html、css、js、图片、音频、视频…
  • 通过 ajax / fetch 获取的数据

浏览器在加载这些资源时,会先检查浏览器缓存中是否存在这些资源,如果存在,则直接从缓存中获取资源,否则,就向服务器发送请求获取资源。

当然对于不同类型的资源,一般会有不同的缓存策略,例如:

  • 对于静态资源,一般使用浏览器自身的 强缓存和协商缓存 机制;
  • 对于 ajax / fetch 获取的数据,一般使用本地存储,例如:localStoragesessionStorageindexedDB 等,当然,也可以使用 vuex / redux 来进行缓存。

3️⃣ DNS 解析

DNS 解析,即域名解析,也就是将我们前面解析 URL 得到的域名解析为 IP 地址(主机地址)。

DNS 解析步骤:

  1. 基于 递归查询本地缓存中查找 DNS 解析记录。

    image

  2. 基于 迭代查询DNS 服务器上查找 DNS 解析记录。

    image

比如对于域名 www.google.com 网址:

  1. 首先在浏览器的 DNS 解析缓存中查找,找不到就去本地 Host 文件中查找,接下来是本地 DNS 解析器缓存、本地 DNS 服务器。
  2. 如果本地没有找到缓存,就会去根域名服务器查找,没有再去顶级域名服务器、权威域名服务器查找,如此的类推下去,直到找到 IP 地址,然后把它记录在本地,供下次使用。

需要注意的是,每一次 DNS 解析的时间,大概在 20 ~ 120 毫秒左右。

所以,简单地说,DNS 的时间开销多少,会影响网页的加载速度快慢!

那么如何优化 DNS 解析呢?

  • 把所有的资源部署在相同服务器的相同服务下,从而减少解析次数;
  • DNS 负载均衡,比如访问 www.baidu.com 的时候,每次响应的并非是同一个服务器(IP地址不同),一般大公司都有成百上千台服务器来支撑访问。DNS可以返回一个合适的机器的IP给用户,例如可以根据每台机器的负载量,该机器离用户地理位置的距离等等,这种过程就是 DNS 负载均衡;
  • 在 DNS 解析次数增加的情况下,我们可以基于 dns-prefetchDNS 预解析,来提高网站的加载速度;

4️⃣ 建立 TCP 连接(TCP 三次握手)

这一步的目的是在获取到服务器 IP (主机地址)后,与其建立连接:

image

为了保证传输通道的稳定性,客户端和服务器都需要知道以下 4 条信息:

  • 客户端可以正常发信息
  • 服务器可以正常接收信息
  • 服务器可以正常发信息
  • 客户端可以正常接收信息

三次握手的过程,实际上就是客户端和服务器之间互相确认这 4 条信息的过程:

  • 第一次握手:客户端 发送一个信息,服务器 接收请求:

    此时,对于:

    • 客户端:知道了客户端可以正常发信息
    • 服务器:知道了客户端可以正常发信息服务器可以正常接收信息
  • 第二次握手:服务器 发送一个信息,客户端 接收请求:

    此时,对于:

    • 客户端服务器可以正常接收信息服务器可以正常发信息 以及 客户端可以正常接收信息,即 客户端 的 4 条信息都确认了;
    • 服务器:知道了 服务器可以正常发信息
  • 第三次握手:客户端 发送一个信息,服务器 接收请求:

    此时,服务器 知道了 客户端可以正常接收信息,那么 服务器 的 4 条信息也都得到了确认。

这样,客户端服务器 之间就建立了稳定的连接通道,可以进行数据传输了。

所以,这里也可以看出三次握手为什么不用两次,或者四次,因为 TCP 作为一种可靠传输控制协议,其核心思想是既要保证数据可靠传输,又要提高传输的效率

5️⃣ 客户端和服务器之间的数据通信

这一步简单来说就是客户端和服务器之间进行数据通信,也就是我们常说的 HTTP 请求和响应。

6️⃣ TCP 四次挥手

这一步的目的在于把建立好的传输通道释放掉。

image

这里以客户端主动关闭连接为例,来说明四次挥手的过程:

第一次挥手

客户端发送一个 FIN,用来关闭客户端到服务器的数据传送,也就是客户端告诉服务器:我已经不会再给你发数据了(当然,在 FIN 包之前发送出去的数据,如果没有收到对应的 ACK 确认报文,客户端依然会重发这些数据),但是,此时客户端还可以接受数据。

其中,FIN = 1,其序列号为 Seq = u(等于前面已经传送过来的数据的最后一个字节的序号加 1),此时,客户端进入 FIN-WAIT-1(终止等待 1)状态。

第二次挥手

服务器收到 FIN 包后,发送一个 ACK 给对方并且带上自己的序列号 Seq,确认序号为收到序号 + 1(与 SYN 相同,一个 FIN 占用一个序号)。此时,服务端就进入了 CLOSE-WAIT(关闭等待)状态。TCP 服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个 CLOSE-WAIT 状态持续的时间。

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

第三次挥手

服务器发送一个 FIN,用来关闭服务器到客户端的数据传送,也就是告诉客户端,我的数据也发送完了,不会再给你发数据了。由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为 Seq = w,此时,服务器就进入了 LAST-ACK(最后确认)状态,等待客户端的确认。

第四次挥手

主动关闭方收到 FIN 后,发送一个 ACK 给被动关闭方,确认序号为收到序号 + 1,此时,客户端就进入了 TIME-WAIT(时间等待)状态。注意此时 TCP 连接还没有释放,必须经过 2 * MSL(最长报文段寿命)的时间后,当客户端撤销相应的 TCP 后,才进入 CLOSED 状态。

服务器只要收到了客户端发出的确认,立即进入 CLOSED 状态。同样,撤销 TCP 后,就结束了这次的 TCP 连接。可以看到,服务器结束 TCP 连接的时间要比客户端早一些。

至此,完成四次挥手。

7️⃣ 浏览器渲染

接下来,就是浏览器把服务器返回的信息(包括 html / css / js / 图片 / 数据 等)进行渲染,最后绘制出对应的页面。

这一部分的内容可见 浏览器渲染原理

8️⃣ 页面展示

最后,浏览器把渲染好的页面展示给用户。

  • 标题: 从输入 URL 到页面展示在浏览器中,发生了什么?
  • 作者: 6dianbiqi
  • 创建于 : 2025-02-18 13:14:38
  • 更新于 : 2025-02-18 14:24:23
  • 链接: https://6dianbiqi.com/2025/02/18/从输入 URL 到页面展示在浏览器中,发生了什么?/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。