最近了解了一下CDN,所以想完整的梳理一下从输入地址到页面展示经历的全流程
1.URL 解析
浏览器首先判断你输入的是关键词还是合法 URL。如果是关键词,调用默认搜索引擎;如果是 URL,则补全协议(如自动将 example.com 补全为 [https://example.com]
2.DNS解析
DNS:把域名(如 www.google.com)转换成计算机能识别的 IP 地址
如果浏览器没有缓存该域名的 IP,它会启动 DNS 查找
浏览器缓存 -> 操作系统缓存(Hosts 文件) -> 路由器缓存 -> ISP(互联网服务提供商)DNS 缓存
CDN 的介入
如果你的架构中配置了 CDN,权威 DNS 最终不会直接返回源站 IP,而是返回一个 CNAME 记录。
- 这个 CNAME 指向 CDN 的 GSLB(全局负载均衡系统)。
- GSLB 会根据用户的地理位置、IP 所属运营商、各 CDN 节点的负载情况,返回一个离用户最近、最健康的 CDN 边缘节点 IP
3.建立网络连接
拿到 IP 后,浏览器与服务器(或 CDN 节点)开始建立 TCP 连接
- 第一次握手: 客户端发送 SYN 报文,进入 SYN_SENT 状态。
- 第二次握手: 服务端收到后,同意连接并发送 SYN-ACK 报文,进入 SYN_RCVD 状态。
- 第三次握手: 客户端收到后,发送 ACK 报文,双方进入 ESTABLISHED 状态
如果是 HTTPS,在 TCP 建连后必须进行 TLS 握手(以 TLS 1.3 为例,已从 TLS 1.2 的两次 RTT 优化为 1次 RTT):
- 客户端发送支持的密码套件和临时公钥(Client Hello)。
- 服务端返回选定的加密算法、服务端证书和它的临时公钥(Server Hello)。
- 双方通过 ECDHE 算法 计算出对称加密的“会话密钥”,后续所有流量均通过此密钥加密。
4.发送HTTP请求数据传输
HTTP/2: 在同一个 TCP 连接上进行多路复用,通过二进制分帧层打破了 HTTP/1.1 的队头阻塞(Head-of-line blocking),允许同时并发无数个请求。
请求到达 CDN 边缘节点:
- 缓存命中(Hit): CDN 节点直接返回缓存的 index.html。
- 缓存失效/未命中(Miss): CDN 节点向源站(Origin Server)发起回源请求。源站可能是你的 Nginx,再反向代理到 Node.js 或 Java 应用程序,生成 HTML 后返回给 CDN,CDN 再缓存并转发给用户
5.浏览器解析与渲染
构建 DOM 树(Document Object Model)
渲染进程的 Tokeniser 开始将 HTML 字符串解析成 Token,并根据嵌套关系构建成一颗树状结构的 DOM。
- 流式解析: 浏览器不需要等整个 HTML 下载完,而是下载多少就解析多少。
- 预加载扫描器(Preload Scanner): 当主线程在解析 HTML 时,另一个轻量级线程会快速扫描后面的 HTML,发现 script、link 等外链资源后,提前发起异步下载,防止网络阻塞。
2. 构建 CSSOM 树(CSS Object Model)
当遇到 <link rel="stylesheet"> 或 <style> 时,浏览器会并行下载并解析 CSS,生成 CSSOM 树。
- CSS 不会阻塞 DOM 的解析,但会阻塞 DOM 的渲染。(因为没有样式,渲染出来的页面会出现闪烁/白屏)。
- CSS 会阻塞后续 JS 的执行。(因为 JS 可能会操作 CSSOM,JS 必须等待 CSSOM 构建完成才能运行)。
3. 处理 JavaScript(阻塞的艺术)
当解析器遇到 <script> 标签时:
- 普通脚本: 暂停 DOM 解析,下载并执行 JS,执行完后再恢复 DOM 解析。
- defer 脚本: 异步下载,不阻塞 DOM 解析,等到 DOM 解析完全结束后,按照在 HTML 中的顺序依次执行。
- async 脚本: 异步下载,不阻塞 DOM 解析,但只要下载完成,立刻暂停 DOM 解析并执行 JS(执行顺序无序)。
4. 生成渲染树(Render Tree)与布局(Layout)
- Render Tree 结合: 浏览器将 DOM 树和 CSSOM 树合并为 Render Tree。注意:display: none 的节点不会出现在渲染树中,而 visibility: hidden 的节点会。
- 布局计算(Layout/Reflow): 浏览器从根节点开始遍历渲染树,计算每个节点在屏幕上的确切几何位置、大小(即计算盒模型)。
5. 分层(Layering)与合成(Compositing)
现代浏览器为了提高性能,并不会把整个页面画在一张画布上,而是像 Photoshop 一样进行分层(Layer)。
- 拥有独立图层的属性:transform: translateZ(0)、will-change、position: fixed、拥有 3D 上下文的 <canvas> 等。
- 栅格化(Rastering): 每一个图层会被分割成许多“图块(Tiles)”,渲染进程中的栅格化线程池会将这些图块转换为位图(Bitmap)。通常会利用 GPU 加速 渲染。
6. 绘制(Painting)与显示
- Paint: 浏览器记录每个图层的绘制指令(比如:先画背景,再画文字)。
- Composit(合成): 浏览器主进程(Browser Process)接收到 GPU 进程生成的位图后,向显卡(GPU)发出指令,将各个图层合成,最终把像素投射到用户的屏幕上。