从输入URL到页面完整展示,发生了什么?

25 分钟

总览:一条 URL 背后的完整链路

面试里问“从输入 URL 到页面展示发生了什么”,通常不是只想听 DNS、TCP、HTTP 三件事。它考察的是你能不能把网络、浏览器内核、缓存、资源调度、渲染性能串成一条完整链路。

可以先用一张流程图式步骤建立全局视角:

输入 URL

URL 解析与补全

检查缓存、Service Worker、预连接等浏览器策略

DNS 解析,拿到目标服务器 IP

建立连接:TCP 三次握手,HTTPS 还要进行 TLS 握手

发送 HTTP 请求,服务端处理并返回响应

处理状态码:重定向、缓存命中、错误页或正常文档

解析 HTML,构建 DOM,同时发现 CSS、JS、图片、字体等子资源

解析 CSS 构建 CSSOM,执行 JavaScript,可能修改 DOM/CSSOM

DOM + CSSOM 生成 Render Tree

Layout 计算几何信息,Paint 生成绘制指令,Composite 合成图层

页面首屏展示,后续资源继续加载与交互响应

这条链路里有两条主线:

  • 网络主线:URL、缓存、DNS、连接、HTTP、重定向、响应内容。
  • 渲染主线:HTML 解析、DOM/CSSOM、JS 执行、布局、绘制、合成、资源加载。

回答时最好先给总览,再逐段展开。这样既不会遗漏关键环节,也能让面试官看到你的结构化表达能力。

URL 解析:浏览器先判断你输入的到底是什么

用户在地址栏输入内容后,浏览器第一步不是立刻发请求,而是判断这段输入属于哪一类。

常见情况有三种:

输入内容浏览器可能的处理
https://example.com/a?b=1识别为完整 URL,直接进入导航流程
example.com补全协议,通常按 https://example.com 尝试访问
浏览器渲染流程识别为搜索关键词,交给默认搜索引擎

一个标准 URL 大致由这些部分组成:

scheme://host:port/path?query#fragment

例如:

https://www.example.com:443/articles?id=10#comment
  • scheme:协议,常见是 httphttps
  • host:域名或 IP,例如 www.example.com
  • port:端口,HTTPS 默认是 443,HTTP 默认是 80
  • path:资源路径,例如 /articles
  • query:查询参数,例如 id=10
  • fragment:片段标识,例如 #comment,通常不会发送给服务器,只在客户端定位页面位置。

如果 URL 中包含中文、空格或特殊字符,浏览器还会做编码处理。比如空格会转成 %20,中文路径会进行百分号编码。这个细节经常出现在“为什么服务端拿到的 URL 和用户输入的不一样”这类追问里。

缓存检查:能不发请求就不发请求

在真正访问网络前,浏览器会先检查本地是否已有可复用结果。缓存的核心目标是减少重复传输,提升加载速度。

浏览器缓存大致可以分成几层:

缓存位置典型作用
Memory Cache当前页面生命周期内复用资源,速度最快
Disk Cache跨页面、跨会话复用资源
Service Worker Cache由站点脚本控制,可实现离线缓存和自定义请求策略
HTTP Cache依据响应头判断强缓存或协商缓存

HTTP 缓存里最常考的是强缓存和协商缓存。

强缓存

如果响应头里存在有效的 Cache-ControlExpires,浏览器可以直接使用本地缓存,不需要向服务器确认。

Cache-Control: max-age=31536000, immutable

这类策略常用于带 hash 的静态资源,例如:

/app.8f3a1c.js
/styles.91ab2.css

文件名变了就代表内容变了,所以旧资源可以放心长期缓存。

协商缓存

如果强缓存过期,浏览器会带上缓存标识向服务器确认资源是否变化。

常见请求头和响应头是:

If-None-Match: "abc123"
If-Modified-Since: Tue, 12 May 2026 10:00:00 GMT

服务器如果判断资源没变,会返回:

HTTP/1.1 304 Not Modified

这时浏览器继续使用本地缓存,但省去了响应体传输。

面试回答要注意:缓存检查不只发生在主文档上,也发生在 JS、CSS、图片、字体等所有子资源上。真正影响页面性能的,往往是这些子资源是否能被稳定复用。

DNS:把域名解析成 IP 地址

浏览器访问服务器需要 IP 地址,但用户输入的是域名,所以要经过 DNS 解析。

DNS 解析通常按缓存优先级逐层查找:

浏览器 DNS 缓存

操作系统 DNS 缓存

hosts 文件

本地 DNS 服务器

根域名服务器

顶级域名服务器

权威域名服务器

解析结果可能是 A 记录,也可能是 AAAA 记录:

  • A 记录:域名到 IPv4 地址。
  • AAAA 记录:域名到 IPv6 地址。
  • CNAME 记录:域名别名,常见于 CDN 接入。

现代站点常通过 CDN 承载静态资源。用户访问 static.example.com 时,DNS 解析结果可能会根据地理位置、运营商和负载情况返回不同节点 IP。这也是同一个域名在不同地区解析结果不同的原因。

如果面试追问 DNS 优化,可以提到:

  • 对关键域名使用 dns-prefetch
  • 减少页面依赖的第三方域名数量。
  • CDN 节点和业务用户分布要匹配。
  • DNS TTL 不能只追求长缓存,也要考虑故障切换速度。

TCP 与 TLS:连接建立决定请求能不能安全发出去

拿到 IP 后,浏览器需要和服务器建立连接。HTTP/1.1、HTTP/2 通常基于 TCP;HTTPS 在 TCP 之上还要进行 TLS 握手。

TCP 三次握手

TCP 三次握手的目标是确认客户端和服务端都具备收发能力。

客户端 → 服务端:SYN
服务端 → 客户端:SYN + ACK
客户端 → 服务端:ACK

三次握手完成后,双方才开始传输应用层数据。

常见追问是:为什么不是两次握手?核心原因是两次握手不能充分确认客户端的接收能力,也容易受历史连接报文影响。三次握手可以让双方都确认对方的发送和接收能力。

TLS 握手

如果使用 HTTPS,还需要 TLS 握手。TLS 的主要目标有三个:

  • 身份认证:通过证书确认服务端身份。
  • 密钥协商:协商后续对称加密使用的密钥。
  • 完整性保护:防止传输内容被篡改。

可以把 TLS 简化理解为:先用非对称加密和证书解决“你是谁”和“怎么安全交换密钥”,再用对称加密高效传输后续数据。

HTTP/2 连接通常可以在一个 TCP 连接上复用多个请求;HTTP/3 则基于 QUIC 和 UDP,减少队头阻塞,并支持更快的连接恢复。面试不一定要展开到 QUIC,但能点到它和 TCP/TLS 的关系,会显得理解更完整。

HTTP 请求与响应:浏览器和服务器开始交换内容

连接建立后,浏览器发送 HTTP 请求。一个请求通常包含请求行、请求头和请求体。

GET /articles/urlToPageRender HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html
Cookie: session=xxx

服务端收到请求后,会经过网关、负载均衡、应用服务、缓存、数据库等环节,最终返回响应。

一个典型响应大致如下:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache
Set-Cookie: uid=123; HttpOnly; Secure

<!doctype html>
<html>...</html>

浏览器会根据响应头决定后续行为:

响应头作用
Content-Type决定响应内容如何解析
Cache-Control控制缓存策略
Set-Cookie写入 Cookie,后续同域请求可携带
Content-Encoding表示 gzip、br 等压缩方式
Location配合 3xx 状态码进行重定向
Content-Security-Policy限制脚本、样式、图片等资源来源

面试里不要只说“服务器返回 HTML”。更准确的说法是:服务器返回一个响应,浏览器根据状态码、响应头和响应体共同决定下一步处理方式

重定向:一次输入可能对应多次请求

用户输入一个 URL 后,不一定只发一次请求。很多页面会经历重定向。

常见场景包括:

  • http://example.com 跳到 https://example.com
  • 裸域名跳到 www 域名。
  • 未登录页面跳到登录页。
  • 旧路径跳到新路径。
  • 服务端按地区或语言跳转。

常见状态码:

状态码含义
301永久重定向,浏览器和搜索引擎会倾向缓存
302临时重定向,历史上使用很广
303通常表示用 GET 请求访问另一个地址
307临时重定向,保持原请求方法
308永久重定向,保持原请求方法

重定向会增加额外的网络往返。如果首屏链路里出现多次 301/302,用户会明显感觉慢。排查首屏性能时,Network 面板里的第一件事就是看主文档是否发生了多次重定向。

HTML 解析:主文档开始变成 DOM

浏览器拿到 HTML 后,会由 HTML Parser 边下载边解析,逐步构建 DOM Tree。

<body>
  <h1>标题</h1>
  <script src="/app.js"></script>
  <link rel="stylesheet" href="/style.css" />
</body>

解析时遇到不同标签会触发不同动作:

标签浏览器行为
<link rel="stylesheet">发起 CSS 请求,CSS 会影响渲染
<script>默认阻塞 HTML 解析,下载并执行脚本
<img>发起图片请求,一般不阻塞 DOM 构建
<iframe>创建独立浏览上下文,成本较高
<meta charset>影响文档字符集解析,位置应尽量靠前

HTML 解析不是等整个文件下载完才开始。浏览器会流式处理内容,这也是为什么服务端流式渲染、SSR、分块传输可以改善首屏体验。

DOM 与 CSSOM:页面结构和样式规则分别成树

DOM 描述页面结构,CSSOM 描述样式规则。浏览器最终需要把两者结合起来,才能知道每个可见节点应该长什么样。

DOM Tree

DOM Tree 来自 HTML,表示节点之间的父子关系。

Document
  └── html
      ├── head
      └── body
          └── div
              └── text

CSSOM Tree

CSSOM 来自 CSS 文件、<style> 标签和内联样式。它会考虑选择器、继承、层叠、优先级和媒体查询。

CSS 不会阻塞 DOM 解析,但通常会阻塞渲染。原因是浏览器必须知道样式规则,才能正确生成 Render Tree。如果没有 CSSOM 就提前绘制,后续样式一到又要大面积重绘,体验会更差。

这也是性能优化里强调“关键 CSS 内联”“非关键 CSS 延后加载”的原因。

JavaScript 执行:既能改 DOM,也可能阻塞解析

JavaScript 是这条链路里最容易影响性能的环节。默认情况下,HTML 解析遇到普通 <script> 会暂停,等脚本下载并执行完成后再继续。

三种常见脚本加载方式区别如下:

写法下载行为执行时机是否保持顺序
<script src="a.js"></script>阻塞解析时下载下载后立即执行保持
<script async src="a.js"></script>异步下载下载完立即执行不保证
<script defer src="a.js"></script>异步下载DOM 解析完成后执行保持

如果脚本里读取样式信息,例如:

const width = element.offsetWidth;

浏览器为了返回准确结果,可能被迫提前完成样式计算和布局,这类现象通常叫强制同步布局。代码里频繁“读布局、写样式、再读布局”,容易造成 layout thrashing。

工程实践里,首屏脚本应该尽量做到:

  • 减少同步阻塞脚本。
  • 非关键脚本使用 defer 或按需加载。
  • 避免在初始化阶段执行大量长任务。
  • 将可延后的逻辑放到用户交互后或空闲时段。

渲染流水线:从 Render Tree 到屏幕像素

当 DOM 和 CSSOM 准备好后,浏览器进入渲染流水线。可以按四步理解:

Style → Layout → Paint → Composite

Style:计算样式

浏览器根据 CSSOM、DOM 节点、继承规则、选择器优先级,计算每个元素最终生效的样式。

Layout:计算布局

Layout 也叫 Reflow,负责计算元素的位置和大小。比如一个块级元素宽度是多少、文本换几行、图片占多高。

会触发布局的典型操作包括:

  • 修改元素尺寸、位置、字体大小。
  • 插入或删除影响文档流的节点。
  • 读取 offsetWidthclientHeight 等布局信息。

Paint:生成绘制指令

Paint 负责把背景、文字、边框、阴影等绘制出来。修改颜色、背景、阴影通常会触发重绘,但不一定触发布局。

Composite:图层合成

浏览器会把某些元素提升为独立图层,最后由合成线程把多个图层合成到屏幕。transformopacity 这类属性通常可以只走合成,不必重新布局和绘制,因此动画性能更好。

但图层不是越多越好。过多图层会占用内存,增加合成成本。will-change 只适合用于确实即将发生变化的元素,不应该全站滥用。

资源加载:主文档之外还有很多关键请求

页面展示不是只有 HTML。浏览器解析过程中会不断发现并调度子资源:

  • CSS:影响渲染,通常优先级很高。
  • JavaScript:可能阻塞解析和交互。
  • 图片:影响视觉完整性和 LCP。
  • 字体:可能导致文字闪烁或不可见。
  • 视频、音频:体积大,通常需要懒加载。
  • JSON 接口:CSR 页面常依赖它生成内容。

浏览器内部有资源优先级调度。一般来说,主文档、关键 CSS、首屏脚本、首屏图片优先级更高,非首屏图片和预加载资源优先级较低。

可以用这些手段影响加载顺序:

<link rel="preconnect" href="https://cdn.example.com" />
<link rel="dns-prefetch" href="https://cdn.example.com" />
<link rel="preload" href="/hero.jpg" as="image" />
<img src="/below-fold.jpg" loading="lazy" alt="" />

这些优化要服务于真实瓶颈:

  • DNS 慢,用 dns-prefetch 或减少第三方域名。
  • 连接慢,用 preconnect
  • 首屏关键资源发现太晚,用 preload
  • 非首屏资源抢带宽,用懒加载。

不要把所有资源都 preload。预加载过多会挤占关键资源带宽,反而让首屏更慢。

性能优化:围绕关键路径做减法

从 URL 到页面展示,性能优化本质上是在缩短关键路径。

阶段常见问题优化方向
URL 与重定向多次跳转收敛域名和协议跳转,避免链式重定向
DNS解析慢、第三方域名多DNS 预解析,减少域名数量,合理使用 CDN
连接TCP/TLS 成本高连接复用,HTTP/2,HTTP/3,preconnect
响应TTFB 高服务端缓存、边缘渲染、数据库优化
HTML关键内容返回晚SSR、流式输出、减少阻塞模板逻辑
CSS阻塞渲染内联关键 CSS,拆分非关键 CSS
JS长任务、阻塞解析代码分割、defer、懒执行、减少主线程工作
图片体积大、发现晚WebP/AVIF、响应式图片、预加载首屏图
渲染频繁回流重绘批量 DOM 操作,优先 transform/opacity 动画

面试中可以结合 Core Web Vitals 表达:

  • LCP:最大内容绘制,关注首屏核心内容出现得快不快。
  • INP:交互到下一次绘制,关注用户操作是否卡顿。
  • CLS:累积布局偏移,关注页面是否突然抖动。

例如首屏图很晚才出现,不能只盯着图片大小,还要检查它是否被 CSS 背景隐藏、是否缺少 preload、是否被 JS 延迟插入、是否受服务端 TTFB 影响。

面试追问:常见问题怎么回答

1. 输入 URL 后一定会进行 DNS 解析吗?

不一定。浏览器、操作系统、本地 DNS、甚至连接池里都可能已有缓存。如果访问的是 IP 地址,也不需要域名解析。已经存在可复用连接时,也可能直接复用连接发送请求。

2. HTTPS 比 HTTP 多了什么?

多了 TLS 握手和加密传输。TLS 解决身份认证、密钥协商和内容完整性问题。成本是握手和加解密开销,但现代 TLS、连接复用、会话恢复已经大幅降低这部分影响。

3. CSS 和 JavaScript 谁会阻塞渲染?

CSS 通常阻塞渲染,因为浏览器需要 CSSOM 才能生成正确的 Render Tree。普通 JavaScript 会阻塞 HTML 解析,并且如果脚本依赖样式计算,还可能等待 CSS 加载完成。asyncdefer 可以改变脚本下载和执行时机。

4. DOMContentLoaded 和 load 有什么区别?

DOMContentLoaded 表示 HTML 解析完成,DOM Tree 已构建完成,不必等待图片、视频等资源加载完成。load 表示页面依赖的资源基本加载完成。很多性能排查里,首屏体验不应该只看 load,还要看 LCP、长任务和关键内容出现时间。

5. 回流和重绘有什么区别?

回流是重新计算布局,影响元素位置和尺寸,成本通常更高。重绘是重新绘制视觉样式,例如颜色、背景、阴影变化。合成只处理图层组合,通常成本更低。性能敏感动画优先使用 transformopacity

6. 为什么首屏慢不一定是网络慢?

首屏慢可能来自很多环节:DNS 慢、连接慢、TTFB 高、HTML 太大、CSS 阻塞、JS 长任务、图片体积大、资源优先级错误、客户端渲染等待接口返回。排查时要用 Performance 和 Network 面板按时间线定位,而不是凭感觉判断。

7. 如果线上页面白屏,你会怎么排查?

可以按链路拆:

  1. 看主文档是否返回成功,是否有重定向、状态码异常、HTML 内容为空。
  2. 看关键 JS/CSS 是否加载失败,是否 MIME 类型错误或跨域失败。
  3. 看控制台是否有运行时异常,是否阻断了应用初始化。
  4. 看接口是否失败,CSR 页面是否因为数据异常没有渲染兜底。
  5. 看是否存在缓存污染、灰度资源不一致、CDN 回源异常。
  6. 看 Performance 时间线,确认是否被长任务、死循环或同步计算卡住。

这个回答比单纯说“看 console 和 network”更完整,因为它沿着真实链路逐层排除。

总结:按链路回答,按瓶颈优化

“从输入 URL 到页面完整展示”可以浓缩成一句话:浏览器先解析输入并检查缓存,再通过 DNS、TCP/TLS 和 HTTP 拿到文档,随后解析 HTML、加载资源、执行脚本、构建 DOM/CSSOM,最后经过样式计算、布局、绘制和合成把页面显示出来。

复习时重点抓住三点:

  • 链路完整:不要只回答网络,也要覆盖解析、执行和渲染。
  • 因果清楚:每个环节为什么存在、会阻塞什么、如何影响性能要说清楚。
  • 能落地排查:遇到白屏、首屏慢、资源加载失败时,能沿着链路定位问题。

面试里最稳的表达方式是:先给总流程,再分网络阶段和渲染阶段展开,最后补充性能优化和排查思路。这样既有广度,也能在追问时继续深入。