从输入 URL 到页面展示到底发生了什么
-
URL解析与预处理:
- 用户输入:用户在浏览器地址栏输入URL(例如
http://www.example.com/path?query=value#fragment)并按下回车。 - 语法检查与编码:浏览器首先检查URL的语法是否正确。如果包含非ASCII字符,浏览器会进行编码(如Punycode处理域名,对路径和查询参数进行百分号编码)。
- HSTS检查:浏览器会检查访问的域名是否在HSTS(HTTP Strict Transport Security)列表中。如果在,并且当前是HTTP请求,浏览器会强制将请求升级为HTTPS。
- 浏览器缓存检查:在发起网络请求之前,浏览器会检查其本地缓存(包括强缓存如Expires, Cache-Control: max-age,和协商缓存如Last-Modified/If-Modified-Since, ETag/If-None-Match)。如果请求的资源在缓存中且未过期(或协商后仍有效),浏览器可能直接从缓存加载,跳过后续大部分网络步骤。
- 用户输入:用户在浏览器地址栏输入URL(例如
-
DNS查询(域名解析):
- 如果缓存未命中或需要验证,浏览器需要将URL中的域名(如
www.example.com)解析为IP地址。 - 查找顺序通常是: a. 浏览器自身的DNS缓存。 b. 操作系统的DNS缓存(包括本地hosts文件)。 c. 路由器的DNS缓存(如果配置了)。 d. 向本地配置的DNS服务器(通常由ISP提供)发起递归查询请求。 e. 本地DNS服务器会负责从根DNS服务器开始,逐级查询顶级域(TLD)DNS服务器、权威DNS服务器,直到找到域名对应的IP地址。
- DNS服务器返回IP地址给操作系统,操作系统再返回给浏览器。
- 如果缓存未命中或需要验证,浏览器需要将URL中的域名(如
-
建立TCP连接:
- 获取到服务器IP地址后,浏览器会与服务器之间建立TCP连接。这通常通过三次握手完成: a. 客户端(浏览器)发送SYN包(同步序列编号)到服务器。 b. 服务器回复SYN-ACK包(同步确认)。 c. 客户端再发送ACK包(确认),TCP连接建立。
- 如果URL是HTTPS协议,在TCP连接建立之后,还需要进行TLS/SSL握手以建立安全的加密通道: a. 客户端发送ClientHello(包含支持的TLS版本、加密套件、一个随机数等)。 b. 服务器回复ServerHello(选择的TLS版本和加密套件、另一个随机数、服务器的数字证书)。 c. 客户端验证服务器证书的有效性(颁发机构、有效期、域名匹配等)。 d. 客户端生成预主密钥(Pre-Master Secret),用服务器证书中的公钥加密后发送给服务器。 e. 服务器用其私钥解密得到预主密钥。 f. 双方根据预主密钥、客户端随机数、服务器随机数共同生成会话密钥(对称密钥)。 g. 双方互发Finished消息,用会话密钥加密,验证握手过程完成。此后所有HTTP数据都将通过此会话密钥加密传输。
-
发送HTTP请求:
- TCP(和TLS/SSL)连接建立后,浏览器构造一个HTTP请求报文。
- 请求报文包含:
a. 请求行(Request Line):如
GET /path?query=value HTTP/1.1。 b. 请求头(Headers):包含Host(目标服务器域名和端口)、User-Agent(浏览器信息)、Accept(可接受的内容类型)、Connection(如keep-alive)、Cookie(如果之前有设置)等。 c. 请求体(Body):对于POST、PUT等请求,会包含要提交的数据。GET请求通常没有请求体。 - 浏览器将HTTP请求报文通过已建立的连接发送给服务器。
-
服务器处理请求并返回HTTP响应:
- 服务器(如Nginx、Apache等Web服务器)接收到HTTP请求。
- 服务器可能会根据配置将请求转发给应用服务器(如Tomcat、Node.js、Django/Flask等)进行业务逻辑处理。
- 服务器端程序执行相关逻辑,可能涉及数据库查询、调用其他服务、文件读取等。
- 处理完成后,服务器构造一个HTTP响应报文。
- 响应报文包含:
a. 状态行(Status Line):如
HTTP/1.1 200 OK或HTTP/1.1 404 Not Found。 b. 响应头(Headers):包含Content-Type(响应内容类型,如text/html)、Content-Length(响应体长度)、Set-Cookie(如果需要设置cookie)、Cache-Control(缓存策略)等。 c. 响应体(Body):实际的资源内容,如HTML文档、CSS文件、JavaScript代码、图片数据等。 - 服务器将HTTP响应报文通过连接发送回浏览器。
-
浏览器接收并处理响应:
- 浏览器接收到服务器返回的HTTP响应报文。
- 根据响应头中的Content-Type,浏览器知道如何处理响应体。例如,
text/html表示这是一个HTML文档。 - 如果状态码是重定向(如301, 302),浏览器会根据响应头中的Location字段发起新的URL请求。
- 浏览器关闭或保持TCP连接(根据Connection头)。HTTP/1.1默认是持久连接(keep-alive),HTTP/2则使用多路复用。
-
浏览器渲染页面: 这是将接收到的资源(主要是HTML、CSS、JavaScript)转换为用户可见页面的过程,主要步骤如下:
- 解析HTML构建DOM树(Document Object Model):浏览器将HTML文本自上而下解析,生成DOM节点,构成DOM树。
- 解析CSS构建CSSOM树(CSS Object Model):浏览器解析HTML中引用的CSS文件(通过
<link>标签)或内联样式(<style>标签),生成CSSOM树,它包含了所有元素的样式信息。 - 构建渲染树(Render Tree):浏览器将DOM树和CSSOM树结合起来,只包含需要显示的节点及其样式信息,形成渲染树。不可见的元素(如
<head>标签内容,或display: none;的元素)不会在渲染树中。 - 布局(Layout / Reflow):根据渲染树,浏览器计算每个节点在屏幕上的确切位置和大小。这个过程也称为回流或重排。
- 绘制(Painting / Repaint):根据布局阶段计算出的信息,浏览器将各个节点绘制到屏幕上,包括文本、颜色、边框、图片等。这个过程也称为重绘。
- 合成(Compositing):对于复杂的页面,浏览器可能会将页面的不同部分绘制在不同的图层(Layers)上,然后将这些图层合成为最终的屏幕图像。这有助于提高滚动和动画的性能(利用GPU)。
- JavaScript执行:在HTML解析过程中,如果遇到
<script>标签,HTML解析器会暂停(除非脚本是async或defer的),下载并执行JavaScript代码。JavaScript可以修改DOM和CSSOM,这可能会触发新的布局(reflow)和绘制(repaint)。
-
后续交互:
- 页面加载完成后(
DOMContentLoaded事件通常在DOM树构建完成时触发,load事件在所有资源如图片加载完毕后触发),用户可以与页面进行交互(点击、滚动、输入等)。 - JavaScript会响应这些用户事件,可能会发起新的AJAX/Fetch请求获取数据、动态修改页面内容,再次触发渲染流程的某些部分。
- 页面加载完成后(