浏览器工作原理:从输入 URL 到页面呈现
Category(分类): Browser Status: 已更新
“从输入 URL 到页面显示”是经典面试题,也是一条很好的前端知识主线。它会串起 URL、DNS、连接、HTTP、缓存、HTML 解析、CSS、JavaScript、布局、绘制和合成。
下面的步骤是便于理解的主路径。真实浏览器会根据缓存、Service Worker、连接复用、HTTP/2 或 HTTP/3、预加载、BFCache 和设备资源进行裁剪、并行或回退。
一、输入和导航
用户可以通过地址栏、链接、表单、脚本或历史记录发起导航。浏览器首先解析输入:完整 URL 按协议处理,缺少协议或看起来像关键词的内容可能交给搜索引擎。
以 https://www.example.com/ 为例,浏览器会确定:
- 协议:
https; - 主机:
www.example.com; - 默认端口:HTTPS 通常是
443,HTTP 通常是80; - 路径:
/; - 查询和片段:查询可能发送给服务器,片段通常只由浏览器处理。
导航前可能发生以下短路:
- HTTP 缓存直接返回资源;
- Service Worker 使用
fetch事件返回 Cache API 或网络结果; - 前进/后退命中 BFCache,恢复已有页面快照;
- 复用已有的 HTTP/2、HTTP/3 或其他适合连接。
二、DNS:把主机名解析为地址
网络连接需要 IP 地址,但域名并不对应永远不变的单个 IP。DNS 可能返回多个 A/AAAA 记录,CDN 也可能根据位置、健康状态和负载返回不同结果。

典型解析链路是:
- 浏览器和操作系统检查本地 DNS 缓存;
- 未命中时向递归解析器请求;
- 递归解析器根据 DNS 层次查询权威服务器;
- 结果按 TTL 缓存,并返回一个或多个地址;
- 浏览器按 IPv6/IPv4、网络策略和连接可用性尝试访问。
“只有第一次访问才会 DNS 解析”不准确。缓存过期、网络变化、记录变更以及新连接建立都可能触发查询。DoH/DoT 可以加密 DNS 查询链路,但不等于给后续 HTTP 自动加密。
三、建立连接:TCP、TLS 与 QUIC
1. HTTP/1.1、HTTP/2 over TCP
如果浏览器使用 TCP,连接通常经过:
客户端 服务端
| -------- SYN ------------> |
| <------ SYN + ACK -------- |
| -------- ACK ------------> |

TCP 提供可靠、有序的字节流。它通过序列号、确认、重传、流量控制和拥塞控制处理网络问题。TCP 三次握手不是每个资源都执行一次:连接可以复用,HTTP/2 还可以在同一连接上并发多个流。
2. TLS 和 HTTPS
HTTPS 是 HTTP over TLS。现代 TLS 1.3 通常使用临时密钥交换生成共享秘密,然后派生对称加密密钥;服务器证书的主要作用是证明服务器身份并提供公钥材料,证书签名不是“用私钥加密所有 HTTP 数据”。
浏览器会检查证书链、域名、有效期、用途和受信任根,并验证握手签名。验证失败时会显示证书错误,不能靠“拿到一个公钥”就确认对端可信。

3. HTTP/3 和 QUIC
HTTP/3 不建立 TCP 连接,而是在 QUIC 上运行。QUIC 使用 UDP 作为底层传输,同时提供可靠流、多路复用、拥塞控制和 TLS 1.3 集成。是否使用 HTTP/3 由客户端和服务端协商,网络不支持时可以回退到 HTTP/2 或 HTTP/1.1。
四、缓存检查和 HTTP 请求
建立连接前后,浏览器都可能使用缓存。典型的 HTTP 缓存过程是:
- 检查
Cache-Control、Expires等新鲜度信息; - 强缓存新鲜时直接使用本地响应;
- 过期后携带
If-None-Match或If-Modified-Since进行验证; - 服务端返回
304时复用本地响应体,否则返回新的响应。
请求的概念结构如下:
GET / HTTP/1.1
Host: www.example.com
Accept: text/html,application/xhtml+xml
Accept-Encoding: gzip, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: session=<省略>
HTTP/2 的真实传输使用二进制帧,上面的文本只是帮助理解请求语义,不代表 HTTP/2 在线路上仍发送同样的请求行文本。
请求通常包含:
- 方法和目标:说明要执行的语义;
- 请求头:内容协商、缓存、Cookie、来源和认证等;
- 请求体:在提交表单、JSON、文件等场景中使用。

五、服务器响应和资源发现
响应包含状态、响应头和响应体:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache
Content-Encoding: br
<!doctype html>
状态码不应只盯着 200:重定向、304、部分成功和错误响应都可能是合法流程。浏览器会根据 Content-Type、响应的 MIME 检查、下载策略和导航上下文决定如何处理响应。
HTML 到达后,预加载扫描器和主解析器会发现依赖资源:
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<link rel="preload" href="/fonts/app.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/app.css">
<script type="module" src="/app.js"></script>
</head>
<body>
<main id="app">加载中</main>
<img src="/hero.webp" alt="首页插图" width="1200" height="630">
</body>
</html>
preload 是提示浏览器尽早获取资源,不会自动让资源被使用;声明错误的 as、crossorigin 或过多 preload 反而会浪费带宽。图片、字体、脚本和 CSS 的优先级应结合真实性能数据调整。
TTFB 是从一次请求开始到收到第一个响应字节的时间,不等于完整页面加载时间,也不等于用户可以交互的时间。现代体验还应关注 FCP、LCP、INP、CLS 等指标。

六、HTML 解析:构建 DOM
浏览器会把 HTML 字节解码为字符,tokenizer 将字符转成 token,tree builder 再根据插入模式和容错规则构建 DOM。

HTML 不是简单的 XML。缺少闭合标签、错误嵌套、表格和 form 等情况都有标准化的错误恢复规则。也就是说,浏览器解析出的 DOM 可能和源代码缩进结构不同。
<!doctype html>
<html>
<head>
<title>页面标题</title>
</head>
<body>
<h1>欢迎</h1>
<p>这是一段文本。</p>
</body>
</html>

解析会被什么阻塞?
<script src="classic.js"></script>
经典脚本可能暂停 HTML 解析,因为脚本可以调用 document.write() 或读取、修改当前 DOM。更推荐使用:
<script src="app.js" defer></script>
<script type="module" src="main.js"></script>
<script async src="metrics.js"></script>
defer在解析完成后执行,并保持经典脚本之间的文档顺序;async下载完成就执行,不能依赖多个 async 脚本的顺序;- 模块脚本默认延迟执行,并按 import 图加载;
DOMContentLoaded会等待 defer 和模块脚本,但不会等待所有图片完成。
CSS 样式通常会阻塞首次绘制;脚本执行有时还需要等待已发现的样式表,但 CSS 不等于总是暂停 HTML tokenizer。字体加载影响文本呈现,却通常不是 HTML 解析器的阻塞点。

七、CSSOM、样式计算和布局树
CSS 文本会被解析,浏览器根据层叠、继承、选择器、媒体查询、容器查询和自定义属性计算每个元素的最终样式。document.styleSheets 可以访问部分 CSSOM,但不应把它理解成浏览器所有内部样式结构。

然后浏览器为可参与布局的内容计算尺寸和位置,形成布局树或 fragment tree。display: none 通常不参加布局,visibility: hidden 通常仍占空间;伪元素、匿名盒和滚动容器会让内部结构比 DOM 更复杂。

早期文章常把 DOM 和 CSSOM 合成后称为 Render Tree。这个说法可以作为教学模型,但现代 Chromium 还会使用布局片段、属性树、绘制块和合成结构,不同引擎的内部名称不能一概而论。
八、绘制、栅格化与合成
布局完成后,浏览器生成背景、边框、文本、阴影和图片等绘制指令。绘制指令会被划分为适合处理的区域或图块,再栅格化为位图,最后由合成器按层叠、裁剪、变换和透明度合成。


transform、opacity 的动画在满足条件时可能只更新合成属性,避免重新布局和绘制,但不是“加了 3D 就一定使用 GPU”。will-change 也只是优化提示,长期给大量元素设置会增加内存和栅格化成本。

九、如何验证页面到底做了什么
不要把固定连接数、固定首包大小、固定图层触发条件和“回流一定重绘整个页面”当作通用规则。可以使用:
- Network:查看 DNS、连接复用、TLS、缓存、优先级和 TTFB;
- Performance:查看 Parse HTML、Recalculate Style、Layout、Paint、Raster、Composite 和 Long Task;
- Elements:查看计算样式、布局盒、层叠上下文和可访问性;
- Lighthouse、CrUX 和 RUM:从实验室和真实用户角度评估体验。