当用户在浏览器地址栏输入 URL 并按下回车,一场跨越网络和计算机内部的复杂协作便拉开了序幕。

DNS 查询

旅程始于 DNS 查询,浏览器需要将用户输入的域名(如 google.com)解析为服务器的 IP 地址。这个过程会依次查询浏览器缓存、系统缓存、路由器缓存,直至向 DNS 服务器发起请求

建立 TCP 链接

拿到 IP 地址后,浏览器会通过三次握手与服务器建立一条可靠的 TCP 连接。如果网站是 HTTPS 的,还需要在此之上进行一次 TLS 握手,以建立加密信道。

浏览器三次握手

TCP 三次握手 - 建立可靠连接

这是所有基于 TCP 通信(包括 HTTP、HTTPS、SSH、电子邮件等)的基石。目标是确保客户端和服务器都确认对方的发送和接收能力是正常的。

  • 第一步:SYN 客户端向服务器发送一个 SYN(Synchronize Sequence Numbers)包,并带上一个初始序列号(Seq = x)。这相当于说:“你好,服务器,我想和你建立连接。我的起始号是 x。”

  • 第二步:SYN-ACK 服务器收到 SYN 包后,必须进行确认。它会回复一个 SYN-ACK 包。这个包包含两部分:

    • ACK(Acknowledgment):确认客户端的序列号,其值为 x + 1。意思是:“我收到了你的起始号 x,下一个我期望收到 x+1。”
    • SYN:同时,服务器也生成自己的初始序列号(Seq = y)。这相当于说:“我也同意建立连接,我的起始号是 y。”
  • 第三步:ACK 客户端收到服务器的 SYN-ACK 包后,需要再次确认。它发送一个 ACK 包,其确认号为 y + 1。意思是:“好的,我收到了你的起始号 y,下一个我期望收到 y+1。”

    至此,TCP 连接建立成功! 双方都确认了彼此可以正常收发数据,可以开始传输 HTTP 数据了。但在 HTTPS 场景下,传输的不是明文 HTTP 数据,而是加密的 TLS 数据。

TLS 握手 - 建立安全加密信道

在可靠的 TCP 连接之上,TLS 握手负责实现安全目标:身份验证(确保你连接的是正确的网站)、加密(确保数据不被窃听)和完整性(确保数据不被篡改)。

一个典型的 TLS 1.2 握手流程如下:

  • 第一步:ClientHello
    • 客户端向服务器发送信息,包括:
    • 支持的 TLS 版本。
    • 支持的密码套件列表(例如  TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)。
    • 一个客户端随机数。
  • 第二步:ServerHello
    • 服务器回应客户端,内容包括:
    • 选定的 TLS 版本和密码套件。
    • 它的数字证书(包含公钥)。
    • 一个服务器随机数。
  • 第三步:验证与密钥交换
    • 客户端验证服务器的证书(是否由可信机构签发、域名是否匹配、是否在有效期内等)。
    • 验证通过后,客户端生成一个“预主密钥”,并用服务器证书中的公钥加密,发送给服务器。
  • 第四步:生成会话密钥
    • 服务器用自己的私钥解密,得到预主密钥。
    • 现在,客户端和服务器都拥有了三个要素:客户端随机数、服务器随机数和预主密钥。  它们各自使用相同的算法,独立生成相同的会话密钥。这个会话密钥将用于后续通信的对称加密。
  • 第五步:握手结束
    • 双方交换“Finished”消息,用刚刚生成的会话密钥加密,以验证整个握手过程是否成功,加密信道是否已就绪。

至此,TLS 安全连接建立成功!  接下来,所有的 HTTP 请求和响应(比如请求 HTML、图片、CSS 等)都会通过这个加密的信道进行传输。

发送 HTTP 请求报文

连接建立后,浏览器便可以发送 HTTP 请求报文。服务器接收到请求后,进行处理(可能涉及数据库查询、业务逻辑计算等),然后返回一个 HTTP 响应报文,其中包含了状态码(如 2OOOK)和响应体(通常是 HTML 内容)。

关键渲染路径

浏览器接收到 HTML 后,渲染引擎开始工作,进入我们之前讨论的关键渲染路径。它会解析 HTML 构建 DOM,解析 CSS 构建 CSSOM。在解析过程中,如果遇到其他资源引用(如 JS、图片、字体文件)浏览器会为这些资源再次发起 HTTP 请求。这些后续请求可能会复用已建立的 TCP 连接(得益于 HTTP 持久连接或 HTTP/2 的多路复用),从而提高效率。最终,页面被渲染出来,并在后续的”水合”过程中绑定交互事件。

几乎每个环节都存在优化空间:DNS 预解析、TCP 预连接、利用 CDN 加速内容分发、启用 HTTP/2 或 HTTP/3、对资源进行压缩和缓存、优化关键渲染路径等等,这些共同决定了最终的用户体验。