当在浏览器中输入URL并按下回车键后,整个网络通信和页面渲染过程会经历多个关键阶段。以下是从网络请求到页面显示的完整流程解析,结合技术原理与通俗比喻,帮助理解这一复杂过程:
🌐 一、域名解析(DNS 解析)
目标:将人类可读的域名(如www.example.com
)转换为计算机可识别的IP地址。
- 本地缓存检查
本地域名解析查询寻顺序:- 浏览器DNS
- 操作系统DNS
- 本地hosts文件
- 向域名服务器发送请求
- DNS服务器查询
若本地无缓存,则向DNS服务器发起递归查询:- 首先询问本地域名服务器(LDNS),若LDNS无记录,会向上级DNS服务器(根域名服务器→顶级域名服务器→权威域名服务器)逐级查询,最终获取IP地址。
- 结果缓存
获取IP后,浏览器和操作系统会缓存该记录,加速后续访问。
二、建立网络连接(TCP/IP 与三次握手)
目标:在浏览器与服务器之间建立可靠的数据传输通道。
- TCP三次握手
- 第一次握手:浏览器向服务器发送SYN包(请求连接),携带随机序列号
Seq=A
。 - 第二次握手:服务器返回SYN+ACK包,确认请求,携带
Seq=B
和确认号Ack=A+1
。 - 第三次握手:浏览器返回ACK包,确认连接,携带
Seq=A+1
和Ack=B+1
。
比喻:打电话时,“你能听到吗?”“我能听到,你呢?”“我也能听到,开始聊吧。”
- 第一次握手:浏览器向服务器发送SYN包(请求连接),携带随机序列号
- HTTPS加密(若URL为HTTPS)
握手后会进行TLS/SSL握手,完成证书验证和密钥协商,确保数据传输加密。
三、发送HTTP请求
目标:浏览器向服务器发送资源请求,请求头中可能包含缓存验证字段。
- 请求报文结构
- 请求行:包含请求方法(GET/POST等)、URL、HTTP版本(如
GET /index.html HTTP/1.1
)。 - 请求头:携带附加信息(如
User-Agent
、Cookie
、Accept
等)。- 协商缓存验证字段:
If-None-Match
: [ETag值]:携带资源唯一标识,验证是否更新。
If-Modified-Since
: [Last-Modified时间]:携带资源最后修改时间,验证是否修改。
- 协商缓存验证字段:
- 请求体:(仅POST等方法存在)携带表单数据、JSON等。
示例:
GET /api/data HTTP/1.1 Host: www.example.com User-Agent: Mozilla/5.0... Cookie: session_id=12345
- 请求行:包含请求方法(GET/POST等)、URL、HTTP版本(如
四、服务器处理请求
目标:服务器生成响应时,通过响应头设置缓存策略。
- 请求解析
服务器解析请求URL和参数,确定需要处理的资源(如HTML、API接口等)。 - 业务逻辑处理
- 若为静态资源(HTML/CSS/图片),直接读取文件;
- 若为动态请求(如API),调用后端程序(Java/Python/Node.js等),可能涉及数据库查询、数据处理。
- 构建响应
生成HTTP响应报文,包含:- 状态码(如200 OK、404 Not Found、500 Internal Server Error);
- 响应头(如
Content-Type
、Cache-Control
),与缓存相关的响应头“- 强缓存策略:
Cache-Control
: max-age=3600:资源在 3600 秒内有效,直接从本地缓存读取(优先级高于 Expires)。
Expires
: Wed, 28 Jun 2025 12:00:00 GMT:资源过期时间,旧版本浏览器兼容。 - 协商缓存策略:
ETag
: “5f9e9f9e9f9e9f9e”:资源内容的哈希值,用于精确验证是否更新。
Last-Modified:
Wed, 28 Jun 2025 10:00:00 GMT:资源最后修改时间。 - 禁止缓存:
Cache-Control: no-store
:禁止任何形式缓存,每次请求都重新获取资源。
- 强缓存策略:
- 响应体(HTML文本、JSON数据、文件二进制等)。
五、浏览器接收响应并解析
目标:将服务器返回的内容渲染为可见页面。
- 响应解析
浏览器解析响应状态码,若为200则继续处理,若为404则显示错误页面。 - HTML解析与DOM树构建
- 逐行解析HTML代码,将标签转换为DOM节点(Document Object Model),形成树状结构。
- 遇到
<script>
标签时,会暂停解析,先下载并执行JS代码(除非设置async
或defer
)。
- CSS解析与CSSOM树构建
解析CSS样式(内联/外部样式表),生成CSSOM(CSS Object Model)树,定义元素样式规则。 - 渲染树(Render Tree)构建
合并DOM树和CSSOM树,生成仅包含可见元素的渲染树,确定每个元素的样式和位置。
六、页面渲染与绘制
目标:将渲染树转换为屏幕上的像素。
-
布局(Layout)
计算渲染树中每个元素的宽高、坐标、层级等几何位置,确定元素在页面中的具体位置。
Reflow
会影响宽高和布局,所以如果有reflow,就要从这一步开始重新渲染, 一般跟大小有关的会触发回流 -
分层(Layer)
将具有复杂样式(如3D变换、透明度、动画)的元素分离为独立图层,便于后续高效处理。
Repiant
可能会从layer/painting
开始重新新渲染, 一般跟颜色相关的改变会触发重绘 -
绘制(Painting)
按图层将元素的颜色、边框、阴影等样式绘制为位图,形成视觉元素的基础图像。
**注:以下4-6过程进入合成线程,不阻塞主线程**
-
分块(Tiling)
将大尺寸图层分割为多个小区域(图块),以便于后续处理和渲染。 -
光栅化(Raster)
将图块转换为屏幕像素,通过GPU加速计算每个像素的颜色和样式。 -
画(Draw)
合成所有图层的像素数据,最终在屏幕上呈现完整的页面内容。(CSS中transform
就是在这一阶段)
- JS执行与交互
执行页面中的JavaScript代码,绑定事件、操作DOM、发起异步请求(如AJAX),实现动态交互。
JS V8引擎解析过程
七、连接关闭与资源加载
目标:处理剩余资源加载和连接管理。
- 资源加载
解析HTML时遇到的图片、字体、子资源(如CSS中的背景图)会异步加载,不阻塞页面渲染。 - TCP四次挥手(若连接关闭)
数据传输完成后,通过四次挥手关闭连接:- 浏览器发送FIN包(请求关闭);
- 服务器返回ACK包(确认关闭请求);
- 服务器发送FIN包(服务器准备关闭);
- 浏览器返回ACK包(确认关闭)。
- 持久连接(Keep-Alive)
现代HTTP/1.1默认保持连接,避免重复握手,提升后续请求效率(HTTP/2进一步优化为多路复用)。
📌 关键流程总结(时序图简化)
浏览器输入URL → DNS解析获取IP → TCP三次握手建立连接 → 发送HTTP请求 →
服务器处理请求 → 返回HTTP响应 → 浏览器解析HTML/CSS/JS → 构建DOM/CSSOM树 →
生成渲染树 → 布局与绘制页面 → 加载剩余资源 → 完成渲染
🔍 扩展:常见优化点
- DNS预解析:通过
<link rel="dns-prefetch">
提前解析域名,减少等待时间。 - 缓存策略:利用响应头
Cache-Control
和ETag
避免重复请求静态资源。 - 懒加载:延迟加载非首屏资源(如图片
loading="lazy"
),加速首屏渲染。 - HTTP/2与HTTP/3:使用二进制分帧、多路复用、QUIC协议等提升传输效率。