在地址栏输入一个 URL 并按下回车后,浏览器不是简单地“向服务器要一个页面”。它可能先使用本地缓存,也可能经过 DNS、TCP、TLS、CDN、反向代理、应用服务和数据库,收到响应后还要解析 HTML、加载子资源并完成渲染。
这些步骤也不是每次都从头发生。DNS 结果可以缓存,连接可以复用,HTTP 响应可能仍然新鲜,Service Worker 甚至可以直接生成响应。本文先沿着一次新的 HTTPS 页面访问建立完整模型,再说明哪些步骤会被复用、跳过或并行执行。
示例 URL 使用:
https://example.com/articles/42?lang=zh#overview先用一张时序图看完整链路
sequenceDiagram
actor U as 用户
participant B as 浏览器
participant C as 本地缓存 / Service Worker
participant D as DNS
participant E as CDN / 反向代理
participant A as 应用服务
participant DB as 缓存 / 数据库
U->>B: 输入 URL 并确认导航
B->>C: 查找可用响应或拦截规则
alt 可以直接满足请求
C-->>B: 返回缓存响应
else 需要网络
B->>D: 查询 example.com
D-->>B: 返回地址和相关记录
B->>E: 建立或复用连接,发送 HTTP 请求
E->>A: 转发请求
A->>DB: 查询缓存、数据库或依赖服务
DB-->>A: 返回数据
A-->>E: 生成 HTTP 响应
E-->>B: 返回响应
end
B->>B: 解析、加载子资源、布局与绘制
B-->>U: 页面可见并逐步可交互这张图是理解链路的骨架,而不是浏览器实现的严格逐行算法。缓存查找、预连接、资源发现和脚本执行可能交错或并行;代理层和服务端也可能比图中更多或更少。
第一步:解析 URL
浏览器首先要把输入解析成结构化 URL。示例各部分如下:
| 部分 | 值 | 含义 |
|---|---|---|
| scheme | https | 使用 HTTPS 语义访问资源 |
| host | example.com | 目标主机名 |
| port | 未显式填写 | HTTPS 默认端口通常是 443 |
| path | /articles/42 | 服务器中的请求路径 |
| query | lang=zh | 提供给服务器或应用的查询参数 |
| fragment | overview | 客户端用于定位文档片段 |
浏览器会处理大小写、百分号编码、相对 URL、国际化域名等细节。URL 不是简单地按冒号和斜杠切字符串;Web 平台采用的是一套明确的解析算法,可以参考 WHATWG URL Standard。
#overview 属于 fragment。它由浏览器在本地用于定位页面中的元素或状态,不包含在发送给 HTTP 服务器的请求目标里。因此,服务器通常看不到用户最终定位到了哪个 fragment。
URL 与 origin
Web 安全模型经常使用 origin。它通常由 scheme、host 和 port 共同确定:
https://example.com:443只改变 path 或 query 不会改变 origin;从 https 改为 http、更换主机或端口则会改变。浏览器的同源策略、Cookie 规则、CORS 和连接复用都会受到这些边界影响,但它们不是完全相同的一套判断条件。
第二步:检查能否避免网络请求
在真正连接服务器前,浏览器可能已经拥有可用结果。为了建立清晰模型,可以把这一层分成 Service Worker 和 HTTP 缓存;实际 Fetch 流程中,它们的交互比“先 A 后 B”更复杂。
Service Worker 可能拦截请求
如果当前站点注册且激活了 Service Worker,并且请求位于其控制范围内,Service Worker 可以处理 fetch 事件。它可以:
- 从 Cache Storage 返回响应;
- 修改请求后访问网络;
- 采用 cache-first、network-first 等应用策略;
- 在离线状态返回预设页面。
Service Worker 缓存策略由站点代码决定,不等同于浏览器的 HTTP 缓存规则。没有安装或尚未接管当前页面时,这一步不会发生。
HTTP 缓存检查 freshness
浏览器 HTTP 缓存会根据请求和已有响应的缓存元数据判断能否复用:
- 响应仍然新鲜时,可能直接使用缓存而不联系源服务器;
- 响应需要验证时,可以携带
If-None-Match或If-Modified-Since; - 服务器返回
304 Not Modified后,浏览器继续使用已有响应正文; no-store等指令可能禁止保存,认证、请求方法和共享缓存还有额外规则。
常见响应头示例:
Cache-Control: public, max-age=3600ETag: "article-42-v3"缓存是否可用不能只看“磁盘里有没有文件”,而要按 HTTP 缓存语义计算。新鲜度、验证和陈旧响应的使用边界定义在 RFC 9111。
第三步:把域名解析成地址
如果请求需要访问网络,客户端要获得目标主机的可用地址。浏览器和操作系统会先检查已有结果;没有可用缓存时,通常把查询交给配置的递归 DNS 解析器。
概念上的完整解析链路是:
浏览器缓存 → 操作系统缓存与 hosts → 递归解析器 → 根名称服务器 → 顶级域名称服务器 → 权威名称服务器递归解析器会替客户端完成后续查询并缓存结果,因此普通浏览器通常不会亲自逐个询问根、顶级域和权威服务器。
常见 DNS 记录
| 记录 | 主要用途 |
|---|---|
A | 将名称映射到 IPv4 地址 |
AAAA | 将名称映射到 IPv6 地址 |
CNAME | 将一个名称指向另一个规范名称 |
HTTPS | 提供 HTTPS 服务端点和协议相关提示等信息 |
每条记录都带有 TTL,用于约束缓存时间。TTL 到期意味着缓存需要刷新,并不保证所有中间系统在同一瞬间得到相同答案。负缓存、递归解析器策略、地理调度和客户端对 IPv4/IPv6 的选择,也会让不同用户观察到不同结果。
第四步:建立或复用连接
浏览器会先检查连接池。如果存在满足 origin、证书、代理和协议条件的可复用连接,就不必每次重新握手。否则,需要根据协商出的协议建立新连接。
HTTP/1.1 与 HTTP/2:先建立 TCP
在常见的 HTTPS 场景中,HTTP/1.1 和 HTTP/2 都运行在 TCP 之上。新连接先通过 TCP 握手建立可靠的双向字节流:
sequenceDiagram
participant C as 客户端
participant S as 服务器
C->>S: SYN
S-->>C: SYN + ACK
C->>S: ACKTCP 负责按序传输、重传和拥塞控制。握手成功只代表传输连接建立,还没有证明 HTTPS 身份,也没有收到页面内容。
HTTPS 继续进行 TLS 握手
TLS 握手主要完成以下事情:
- 协商协议版本和密码套件;
- 服务器发送证书链,客户端检查信任链、有效期和主机名;
- 双方通过密钥交换得到会话密钥;
- 后续应用数据获得机密性和完整性保护;
- 通过 ALPN 等机制协商使用
h2还是http/1.1。
TLS 保护的是传输中的内容和对端身份验证,不会自动保证应用没有漏洞,也不会隐藏所有网络元数据。TLS 1.3 的协议细节见 RFC 8446。
HTTP/3:QUIC 中集成 TLS
HTTP/3 不先建立 TCP 连接,而是运行在 QUIC 之上;QUIC 通常通过 UDP 承载,并把 TLS 1.3 握手集成进传输层。客户端可以通过既有配置、Alt-Svc 或其他服务发现机制得知服务器支持 HTTP/3;如果 UDP 路径不可用,客户端通常仍可尝试基于 TCP 的 HTTP/2 或 HTTP/1.1。
第五步:发送 HTTP 请求
连接就绪后,浏览器把导航意图表达成 HTTP 请求。用 HTTP/1.1 的可读形式表示,大致如下:
GET /articles/42?lang=zh HTTP/1.1Host: example.comAccept: text/html,application/xhtml+xmlAccept-Encoding: gzip, brUser-Agent: <browser identifier>Cookie: <applicable cookies>请求主要包含:
- method:例如
GET、POST; - request target:这里是 path 和 query,不含 fragment;
- headers:描述主机、可接受格式、缓存条件、身份状态等;
- body:导航 GET 通常没有正文,提交数据的请求可能有。
HTTP/2 和 HTTP/3 不会按上面这段文本原样在线路上传输。它们把语义编码进二进制帧,并用 :method、:scheme、:authority、:path 等伪首部表达关键字段。开发者工具会把这些内容还原成易读视图。
Cookie 和认证信息何时发送
浏览器只会发送符合域、路径、过期时间、Secure、SameSite 等条件的 Cookie。认证也可能使用 Authorization 请求头或其他机制。
第六步:经过网络中间层
请求抵达应用前,可能经过多个中间层:
| 中间层 | 可能承担的职责 |
|---|---|
| 正向代理 | 代表客户端访问网络、实施组织策略 |
| CDN 边缘节点 | 缓存静态或可缓存响应、就近接入、抵御部分攻击 |
| WAF | 按规则检查和阻断可疑请求 |
| 负载均衡器 | 在多个后端实例之间分配流量 |
| 反向代理 | TLS 终止、路由、压缩、缓存、请求头处理 |
TLS 可能在 CDN 或反向代理终止,然后由它与后端建立新的受保护连接。此时客户端建立的是到边缘节点的安全连接,不代表同一条 TLS 会话一直延伸到最终应用进程。
代理可能添加 Forwarded、X-Forwarded-For、X-Forwarded-Proto 等头。应用只有在请求确实来自受信代理且代理会清理外部伪造值时,才能把这些头作为客户端信息依据。
第七步:服务器和应用处理
请求进入服务端后,常见处理链路如下:
监听套接字 → Web 服务器或应用容器 → 路由匹配 → 中间件 → 身份认证与授权 → 输入校验 → 业务逻辑 → 缓存、数据库或外部服务 → 生成响应路由和中间件
服务器根据 method、host 和 path 等信息找到处理逻辑。日志、限流、追踪、认证、CORS、内容解析等功能常由中间件完成。中间件顺序会影响结果,例如在身份认证之前读取受保护用户信息通常得不到有效身份。
应用缓存和数据库
应用可能先查询内存缓存或 Redis 等外部缓存;未命中时再通过连接池访问数据库。一次数据库访问又可能经历:
- 从连接池获取连接;
- 解析或复用预编译语句;
- 执行查询和事务;
- 读取索引页或磁盘数据;
- 返回结果并序列化。
并非每个请求都会访问数据库。静态资源可能由 CDN 直接返回,健康检查可能只读取进程状态,写请求则可能涉及事务、消息队列或多个依赖服务。
延迟会累积,也会并行
服务端总耗时不一定是每一步简单相加。互不依赖的查询可以并行,连接池等待、锁竞争、缓存穿透、慢查询和下游超时则会显著增加尾延迟。排查时需要端到端 trace 或分层指标,不能只看应用函数的执行时间。
第八步:生成并返回 HTTP 响应
应用完成处理后生成状态码、响应头和正文。HTTP/1.1 的可读表示可能是:
HTTP/1.1 200 OKContent-Type: text/html; charset=utf-8Content-Encoding: brCache-Control: public, max-age=300Content-Length: 4821
<!doctype html>...状态码表达处理结果
2xx:请求已按相应语义成功处理;3xx:需要重定向或可以使用缓存表示;4xx:请求一侧存在问题,例如未认证、无权限或资源不存在;5xx:服务器处理请求时失败。
状态码只说明 HTTP 层约定的结果。一个返回 200 的接口仍可能把业务错误包装在 JSON 中;这会增加调用方判断成本,API 设计应保持语义清晰。
响应可能被压缩、缓存或流式发送
服务器或代理可以根据 Accept-Encoding 选择 gzip、Brotli 等内容编码。缓存头决定后续是否可复用。大响应也可能分块或流式传输,让浏览器在完整正文到达前开始处理。
对于 HTTP/2 和 HTTP/3,响应数据会被拆成帧放入对应 stream。协议的多路复用让同一连接上可以交错传输多个资源,但应用优先级、服务端调度和带宽仍会影响实际完成顺序。
第九步:浏览器解析和渲染
收到 HTML 字节不等于页面已经完成。浏览器还需要把响应转为可显示、可交互的文档。
从字节到 DOM
浏览器根据响应头、BOM 和 HTML 规则确定字符编码,然后由 tokenizer 与 parser 构造 DOM。HTML 解析具有错误恢复规则,遇到不规范标签时不一定直接失败。详细算法见 HTML Standard:Parsing HTML documents。
解析器发现 <link>、<script>、<img> 等元素后,会发起更多请求。浏览器还可能通过预加载扫描器提前发现资源,因此“解析完 HTML 后才下载 CSS 和图片”并不准确。
CSS、JavaScript 和渲染流水线
可以用下面的概念流程理解:
HTML → DOM ┐ ├→ render tree → layout → paint → compositeCSS → CSSOM┘- CSSOM 表示计算样式所需的 CSS 结构;
- render tree 只包含参与当前渲染的节点及样式信息;
- layout 计算元素几何位置和尺寸;
- paint 生成绘制指令;
- composite 把不同图层组合到屏幕。
JavaScript 可以读取和修改 DOM/CSSOM,也可能触发新的样式计算、布局和绘制。经典同步脚本可能阻塞 HTML 解析;defer、async 和模块脚本具有不同的下载与执行时机。
HTTP/1.1、HTTP/2 与 HTTP/3 的主要区别
| 维度 | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| 常见底层传输 | TCP | TCP | QUIC(通常承载于 UDP) |
| 消息表达 | 文本起始行和首部 | 二进制帧 | 基于 QUIC stream 的二进制帧 |
| 首部压缩 | 无内建动态压缩 | HPACK | QPACK |
| 同一连接并发 | 没有独立 stream 多路复用 | 多个并发 stream | 多个并发 QUIC stream |
| 丢包影响 | 依赖 TCP 按序交付 | TCP 丢包可能暂时阻塞连接上的所有 stream | 一个 stream 的丢失数据不必阻塞其他 stream 的交付 |
| HTTPS 协商 | TLS 后使用 HTTP/1.1 | TLS ALPN 常协商 h2 | QUIC 内集成 TLS 1.3,使用 h3 标识 |
HTTP/1.1:持久连接但没有 stream 多路复用
HTTP/1.1 默认支持持久连接,可以在同一 TCP 连接上依次发送多个请求。协议存在 pipelining 机制,但响应必须与请求顺序对应,且浏览器实践中没有成为解决并发加载的主要方式;客户端常通过多条连接提高并发。
HTTP/1.1 报文和连接管理定义在 RFC 9112。
HTTP/2:在一条 TCP 连接上复用多个 stream
HTTP/2 把消息拆成带 stream 标识的帧,使多个请求和响应可以在同一连接中交错传输。一个慢响应不必在 HTTP 层阻止其他响应发送,但所有 stream 仍共享同一 TCP 字节流;发生丢包时,TCP 必须补齐缺失数据后才能继续按序交付,因而可能暂时影响全部 stream。
HTTP/2 的帧和 stream 语义定义在 RFC 9113。
HTTP/3:把 HTTP 映射到 QUIC stream
HTTP/3 使用 QUIC stream 承载请求。QUIC 在传输层区分 stream,因此某一 stream 丢失的数据需要重传时,其他已经完整到达的 stream 不必等待它恢复。这减少了 HTTP/2 在 TCP 层的跨 stream 队头阻塞,但拥塞、带宽和应用调度仍然是共享约束。
QUIC 还使用连接 ID 支持连接迁移等能力,但网络切换后能否无感保持连接取决于客户端、服务器和路径条件,不能把它理解为永不掉线。HTTP/3 的规范见 RFC 9114。
冷访问和热访问有什么不同
完整链路常被称为“冷访问”。再次访问时,下列状态可能减少工作:
| 可复用状态 | 可能省去或缩短的步骤 | 仍需注意 |
|---|---|---|
| DNS 缓存 | 完整 DNS 查询 | TTL、网络和解析器变化 |
| 已有连接 | TCP/QUIC 及部分握手 | 空闲超时、连接上限、origin 与证书条件 |
| TLS 会话恢复 | 完整 TLS 协商成本 | 由双方配置和会话状态决定 |
| HTTP 缓存 | 网络传输或完整正文下载 | freshness、验证和缓存指令 |
| CDN 缓存 | 回源与应用处理 | 缓存键、失效策略、地域节点 |
| Service Worker | 甚至可以离线响应 | 只在已安装且控制页面时生效 |
因此,“打开一个网页需要几次往返”没有脱离上下文的固定答案。协议版本、缓存状态、连接是否复用、重定向次数、资源依赖图和网络质量都会改变结果。
从现象反推链路问题
DNS 解析失败
dig example.com Adig example.com AAAA先比较系统或指定解析器的结果。DNS 正常只说明得到了记录,不说明目标端口或应用健康。
TCP、TLS 或 HTTP 失败
curl -v https://example.com/curl -I -L https://example.com/curl -v 可以观察地址选择、连接、TLS 和 HTTP 头;-I -L 适合查看重定向链。具体是否支持 --http2 或 --http3 取决于本机 curl 的构建和依赖。
浏览器里页面很慢
开发者工具的 Network 面板可以观察:
- 请求是否来自 memory cache、disk cache 或 Service Worker;
- DNS、连接、TLS、等待首字节和内容下载时间;
- 重定向链和协议版本;
- 哪些 CSS、字体、脚本或图片阻塞关键渲染路径;
- 响应头是否允许缓存和压缩。
各浏览器的时间字段名称和精确边界并不完全相同。服务端慢应结合 trace、访问日志、应用指标和数据库指标判断,不能只靠前端瀑布图猜测内部原因。
完整流程总结
一次新的 HTTPS 页面访问,可以按下面的因果关系理解:
解析 URL → 检查 Service Worker 与缓存 → 解析 DNS → 建立或复用 TCP/TLS 或 QUIC 连接 → 发送 HTTP 请求 → 经过 CDN、代理与负载均衡 → 应用处理并按需访问缓存、数据库和外部服务 → 返回 HTTP 响应 → 浏览器解析 HTML、加载子资源并渲染真正排查问题时,不要把这条链背成固定顺序,而要先问三个问题:哪些步骤本次实际发生了,哪一层提供了可观测证据,哪一段延迟或错误能够被独立复现。这样才能把“网页打不开”逐步缩小成 DNS、连接、TLS、HTTP、应用还是渲染问题。
参考标准
分享文章
生成精美分享图或复制链接,与更多人分享本文。
继续阅读
换条路线
从其他文章中稳定抽取
最后更新于 ,距今已过 9 天
部分内容可能已过时