输入 URL 后到页面渲染
在浏览器中输入 URL 到页面渲染的整个过程可以分为多个步骤。这个过程涉及浏览器、操作系统、网络以及服务器的协作。我们可以把这个过程概括为以下几个主要阶段:
1. DNS 解析
当你在浏览器中输入一个 URL 并按下回车时,浏览器首先会解析这个 URL。URL 通常包括协议(如 http
或 https
)、域名(如 example.com
)或 IP 地址、端口和路径。
如果 URL 包含的是域名而不是IP地址,浏览器需要通过DNS(域名系统)解析来获取该域名对应的服务器IP地址。
本地域名服务器查询:浏览器首先会查找本地缓存中是否有该域名对应的 IP 地址。如果缓存中找不到,它会向本地域名服务器发起请求。
根域名服务器查询:如果本地域名服务器没有找到结果,它会请求根域名服务器。根域名服务器会返回与该域名相关的顶级域名服务器(如
.com
、.net
等)的地址。顶级域名服务器查询:接下来,本地域名服务器向返回的顶级域名服务器发起查询,顶级域名服务器会返回具体管理该域名的服务器地址。
目标域名服务器查询:本地域名服务器向目标域名服务器发起查询,目标服务器返回具体的 IP 地址。
DNS 缓存:本地服务器将查询到的 IP 地址返回给用户,并且会将该 IP 地址缓存起来,供未来快速访问。
2. TCP 协议 —— 三次握手(建立连接)
获取了服务器的 IP 地址后,浏览器会与服务器建立 TCP 连接。这时会涉及三次握手的过程:
三次握手步骤:
客户端发送连接请求(SYN) :客户端向服务器发送一个带有 SYN 标志位的请求,表示希望建立连接。此时客户端处于 SYN-SENT 状态。
服务器确认请求并回复(SYN + ACK) :服务器收到连接请求后,会回复一个带有 SYN 和 ACK 标志的报文,表示接受连接请求并确认。此时服务器进入 SYN-RECEIVED 状态。
客户端确认收到回复(ACK) :客户端接收到服务器的确认后,再次发送一个带有 ACK 标志的确认信息,表明连接建立完成。此时双方都进入 ESTABLISHED 状态,连接成功建立。
为什么一定要三次握手,两次行不行?
这时,面试官就会问,一定要三次握手吗?两次握手不行吗?答案当然是不行;
如果只使用两次握手,有可能会出现以下情况:
客户端发送了一个连接请求SYN报文后,由于网络拥塞等原因,这个报文丢失了, 客户端超时后重新发送了一个新的SYN报文,建立了连接并进行了数据传输。但是在连接关闭之后, 第一次发送的那个SYN报文突然又到达了服务端,按照两次握手的方式,服务端会误以为这是一个新的连接请求, 并发送SYN+ACK进行确认,进而建立一个无效的连接,浪费性能。而三次握手就能避免这种情况, 因为服务端在收到第一个SYN报文时会回复SYN+ACK,但如果没有收到客户端的确认ACK,就不会建立连接。
3. HTTP 数据传输
TCP 连接建立之后,浏览器会向服务器发送 HTTP 请求进行数据传输。关于 HTTP 协议有以下几个版本:
HTTP 0.9 —— 超文本传输协议的起源
HTTP 0.9 是最初版本的 HTTP 协议,专为实验室设计,用于传输简单的 HTML 文本。这个版本极为简化,只有请求行,格式为 GET /index.html
。服务器接收请求后,只返回 HTML 文本内容,且使用 ASCII 编码。虽然 HTTP 0.9 能够基本传输超文本文件,但它无法传输其他类型的资源文件,且没有请求头或响应头,导致服务器与客户端之间的通信能力非常有限。
HTTP 1.0 —— 支持更多资源的传输
随着互联网的发展,不仅仅是 HTML 文件,还有图片、音频、视频等多种类型的资源需要传输,HTTP 0.9 已无法满足需求。因此,HTTP 1.0 增加了请求头和响应头,允许客户端和服务器之间的更多交流,传输不同类型的资源。
请求头:客户端可以通过请求头来告知服务器所期望的数据类型和格式,如:
accept:text/html
—— 表示期望返回 HTML 文件。accept-encoding: gzip, deflate, br
—— 指定支持的压缩格式。accept-language: zh-CN,zh;q=0.9,en;q=0.8
—— 指定优先的语言。accept-charset: utf-8
—— 指定使用的字符编码。响应头:服务器通过响应头告知客户端返回的数据类型、编码方式等,如:
content-type: text/html
—— 返回 HTML 文件。content-encoding: gzip
—— 指定内容已使用 gzip 压缩。
此外,HTTP 1.0 还引入了 HTTP 状态码,如 200(成功)、404(未找到)、500(服务器错误),用于指示请求的处理结果。
HTTP 1.1 —— 持久连接与虚拟主机支持
HTTP 1.0 的一个主要问题是短连接。每次请求都会建立一次 TCP 连接,响应结束后就关闭连接,这样对服务器资源消耗较大。为了解决这个问题,HTTP 1.1 引入了长连接,即 TCP 连接在一次请求结束后不会立即关闭,多个请求可以复用同一个连接。这提高了性能,减少了连接建立和断开的开销。
HTTP 1.1 版本有以下一些特性:
HTTP 队头阻塞:HTTP 1.1 虽然支持长连接,但多个请求在同一条 TCP 连接中发送时,如果前一个请求未完成,后面的请求会被阻塞,导致效率降低。
虚拟主机支持:HTTP 1.1 增加了
HOST
头字段,允许一台服务器通过一个 IP 地址托管多个域名。Cookie 支持:HTTP 1.1 通过 Cookie 实现了用户状态管理,使得网站可以记住用户的登录状态等信息。
HTTP 2.0 —— 多路复用与头部压缩
虽然 HTTP 1.1 的长连接改善了性能,但仍存在带宽利用率低的等问题。主要体现在以下方面:
TCP的慢启动:TCP的慢启动算法是用来控制新建立的连接初期的流量,避免突然大量的数据涌入网络造成拥塞。在慢启动阶段,发送方最初只会发送少量的数据段(通常是一个MSS,最大报文段长度),然后根据收到的确认逐步增加发送速率。
同时开启的多条TCP连接相互竞争带宽:当一个客户端同时与服务器建立了多个TCP连接时,这些连接可能会相互竞争有限的带宽资源。
http队头阻塞:HTTP/1.1中的队头阻塞是指在一个TCP连接中,后续请求的处理必须等待前面请求的响应才能开始的问题。即使服务器已经准备好发送多个响应,但如果前面的响应没有完全发送完毕,后面的响应也无法开始传输。
对此 HTTP 2.0 引入了多项优化措施,提升了协议效率:
多路复用:HTTP 2.0 在单一 TCP 连接上支持同时发送多个请求和响应,避免了 HTTP 1.1 中的队头阻塞。它通过一个二进制分帧层将请求和响应分解为多个帧,每个帧带有唯一的 ID,浏览器和服务器通过 ID 来区分和组合数据。这大大提高了传输效率,且避免了多个 TCP 连接之间的带宽竞争。
优先级控制:在多路复用中,重要的资源可以被打上高优先级标记,服务器会优先传输这些资源(例如页面的 CSS 和 JavaScript 文件)。
头部压缩:HTTP 2.0 引入了头部压缩,减少了请求和响应中头部字段的冗余数据,提升了带宽利用率。
HTTPS VS HTTP
HTTPS 是在 HTTP 基础上增加了 TLS(Transport Layer Security)协议 的加密层,用来确保数据传输的安全性。它的主要工作机制包括:
对称加密:传输的数据会使用双方共享的密钥进行加密和解密,保证数据传输的机密性。
非对称加密:在通信开始时,客户端生成密钥,服务器生成公钥和私钥。客户端使用服务器的公钥加密其生成的密钥,并发送给服务器,服务器用私钥解密,确保双方可以安全地共享一个密钥用于后续的对称加密。
通过 HTTPS,传输的数据在网络中是加密的,避免了敏感信息被窃取或篡改。
TCP 和 UDP 的区别
TCP(Transmission Control Protocol)—— 可靠的传输协议
TCP 是一种面向连接的传输层协议,它提供可靠、顺序的数据传输,广泛应用于对数据传输质量要求较高的场景。
特点:
可靠性:
建立连接:TCP 通过三次握手机制确保客户端和服务器成功建立连接后,才开始传输数据。通过四次挥手来安全断开连接,保证传输完整性。
流量拥塞控制:TCP 内置了流量控制和拥塞控制机制,通过检测网络的负载情况,自动调节数据传输速度,避免网络过载。
超时重传机制:如果数据包在传输中丢失或没有被及时确认,TCP 会自动触发重传,确保所有数据都能准确无误地到达目的地。
有序性:
TCP 将传输的数据分成多个包,使用序列号来确保数据包的顺序传递。如果数据包到达顺序有误,TCP 会根据序列号进行重新排序,确保数据按照正确顺序到达接收方。
应用场景:
网页浏览:保证网页内容的完整性。
文件传输:如 FTP 协议,确保文件不丢失、不损坏。
电子邮件:确保邮件内容的准确性。
TCP 适用于需要高可靠性传输的场景,如:
UDP(User Datagram Protocol)—— 高效的传输协议
UDP 是一种面向无连接的传输层协议,强调传输速度和效率,而不保证数据的可靠传输和顺序。UDP 常用于对实时性要求较高的应用场景。
特点:
不可靠性:
无连接:UDP 在发送数据前不需要建立连接,直接将数据包发送给目标地址,不会等待确认。这样虽然减少了延时,但也带来了不可靠性。
无流量控制和拥塞控制:UDP 不具备 TCP 的流量控制和拥塞控制功能,数据包的发送不会受到网络状况的调节,因此有可能导致数据丢失或过载。
不管丢包:UDP 不会检测数据包是否丢失,也不会进行重传。这使得它在传输过程中,可能有数据丢失,但这也带来了高效性。
高效:
由于没有建立连接的过程,也没有流量控制和丢包重传机制,UDP 的传输速度快,延迟低,特别适合需要快速传输数据的场景。
应用场景:
直播:如视频或音频直播,允许偶尔的数据丢失而不影响整体体验。
在线游戏:游戏中的实时性要求高,UDP 的低延迟可以提供更流畅的游戏体验。
视频通话:实时视频和音频需要低延迟传输,丢失少量数据不会影响通话质量。
UDP 适用于对传输可靠性要求不高,但对实时性要求较高的应用场景,如:
HTTP 3.0 —— 解决队头阻塞与连接延迟
虽然 HTTP 2.0 引入了多路复用,但它仍然依赖于 TCP 协议,存在TCP 队头阻塞的问题。HTTP 3.0 基于 QUIC(Quick UDP Internet Connections)协议,这是一个集成了 TCP 优势并基于 UDP 的全新协议,解决了 TCP 的一些固有问题。
队头阻塞的解决:在 TCP 中,超时重传机制导致队头阻塞,即一个数据包丢失后,后续所有数据包都必须等待重传的完成。QUIC 通过多条独立的数据流,丢失的包不会影响其他包的传输。
快速握手:TCP 在建立连接时需要三次握手,而 QUIC 的连接建立速度更快,减少了握手延迟,提升了页面加载速度。
集成 TLS 加密:QUIC 集成了 TLS 加密层,进一步增强了数据传输的安全性。
4. TCP 协议 —— 四次挥手(断开连接)
在通信完成后,浏览器和服务器通过四次挥手来断开 TCP 连接。四次挥手确保双方都能安全地结束数据传输,不会丢失任何未发送的内容。
四次挥手步骤:
客户端发送断开请求(FIN) :客户端发出一个带有 FIN 标志位的报文,表示希望断开连接,进入 FIN-WAIT-1 状态。
服务器回复确认(ACK) :服务器接收到断开请求后,返回一个 ACK 报文,表示确认接收到断开请求,但它可能还有数据要发送,进入 CLOSE-WAIT 状态。
服务器完成数据传输后发送断开请求(FIN) :服务器发送完剩余数据后,向客户端发出 FIN 请求,表示它准备好断开连接,进入 LAST-ACK 状态。
客户端确认断开(ACK) :客户端接收到服务器的 FIN 报文后,返回一个 ACK 报文,进入 TIME-WAIT 状态,并等待 2MSL(最大段生命周期)时间,确保服务器接收到确认消息。随后,客户端和服务器都进入 CLOSED 状态,连接正式断开。
5. 浏览器开始渲染页面
浏览器接收到服务器的响应后,开始处理响应内容。这个过程包含多个步骤,尤其是在渲染 HTML 页面时非常复杂:
HTML 解析与 DOM 树的构建
当浏览器开始加载页面时,首先会解析 HTML 文件,并将 HTML 转换为 DOM 树(Document Object Model)。DOM 树中的每个节点代表一个 HTML 标签,它们以树状结构表示页面的层次关系。
CSS 解析与 CSSOM 树的构建
与此同时,浏览器会解析 CSS 文件或嵌入式样式,构建 CSSOM(CSS Object Model)树。CSSOM 树存储了每个 DOM 节点的样式信息。
合成构建 Render Tree
浏览器将 DOM 树和 CSSOM 树结合起来,生成一棵新的渲染树(Render Tree) 。渲染树的每个节点对应一个可见的元素,它包含了 DOM 元素的视觉信息(例如尺寸、位置、颜色等)。在这个过程中,某些不参与渲染的元素(如 display: none
的元素)不会被添加到渲染树中。
回流(Reflow)
一旦渲染树创建完毕,浏览器开始计算每个元素在页面中的具体位置和大小,这个过程称为布局(Layout) ,也称为回流(Reflow) 。它决定了页面的几何属性,包括每个元素的尺寸、位置、边距等。
首次布局:在页面初次渲染时,浏览器会遍历渲染树,为每个可见元素计算它们在页面中的确切位置和尺寸。这个过程称为初次回流,因为页面的每个部分都要计算和排列。
后续回流:当页面的元素结构或布局属性(如
width
、height
、margin
等)发生变化时,浏览器需要重新计算这些元素及其相关元素的布局,这个过程也被称为回流。
回流的触发原因:
DOM 结构的变化(增加或删除元素)。
元素的几何属性(如宽度、高度、边距)发生变化。
浏览器窗口大小的变化。
读取某些会导致重新计算布局的属性(如
offsetHeight
、clientWidth
等)。
重绘(Repaint)
布局完成后,浏览器开始为每个元素填充颜色、绘制边框、应用阴影和文字等,这个过程称为绘制(Paint) ,如果布局没有发生变化但样式发生了变化(例如颜色、背景、字体等),则会触发重绘(Repaint) 。
重绘的触发原因:
元素的视觉属性(如
color
、background-color
、border-color
等)发生变化。虽然元素的几何属性没有变化,但它的外观发生了变化,浏览器需要将它重新绘制出来。
重绘的代价较回流小,因为它不涉及重新计算布局,只需要重新绘制改变了样式的部分。
总结
从输入 URL 到页面的渲染是一个复杂的过程,在数据传输时,首先需要进行TCP建立连接,再通过HTTP进行数据得传输;然后再到页面的渲染,重绘不一定会触发回流,而回流是一定会导致重绘的,因为回流之后,需要重新去绘制页面。