前言
相信很多掘友和我一样都是前端,我们前端打交道最多的就是浏览器了,对于浏览器我们也会去看它的底层原理,也能说上来其工作流程,但却老是忘了,那么就完整的梳理一遍,形成完整的知识链,深度理解浏览器这个老伙伴
今天来看是:从输入URL到页面加载的全过程
- 输入URL并解析
- 用户:在浏览器中输入URL地址,并回车。
- 浏览器:检查输入的URL地址是否合法,并解析。
- 缓存查找 因为浏览器的缓存机制,在输入URL之后浏览器会先查看浏览器缓存/系统缓存-路由缓存中是否存在该页面,如果有则显示页面内容,没有则进入下一步。
- DNS域名解析 浏览器向DNS服务器发起请求,解析该URL中的域名对应的IP地址。
- 步骤:查浏览器缓存 → 2. 查系统 hosts 文件 → 3. 查本地DNS缓存 → 4. 递归查询 DNS 服务器。
如果DNS服务器没有这个域名的记录,这会执行迭代查询,从根DNS服务器开始向更高级的DNS服务器发送查询。(域名的结构通常是从右到左,从最高级别到低级别,例如 www.juejin.cn中 .cn是顶级域,juejin.cn是二级域,www.juejin.cn是三级域,也就是子域)

那为什么要DNS解析呢? 这是一个很基础但也非常关键的问题,涉及到我们日常访问网站时"背后的魔法"。通俗来讲 URL 域名其实是"人类语言",方便我们来记忆的,但计算机和网络设备并不能识别这个名字,所以需要DNS解析将"人类语言"解析为"机器语言:IP地址"
- 建立TCP连接
为什么要TCP连接? :其实网络通信本质是不可靠的,数据容易丢失、乱码、重复,那为了保证数据的可靠传输和顺序传递,以及进行流量和拥塞控制,在发送请求之>前需要先建立TCP连接,而不是直接向服务器请求数据。
-
TCP 连接的基本原理
建立TCP连接的过程是通过客户端和服务器端相互发送
TCP报文(TCP协议传输数据的基本单位,一个TCP报文由首部(Header)和数据部分(Data)组成)
确认连接的,TCP报文
有6个控制标志- URG: Urgent紧急的(优先发送紧急数据)
- ACK : 确认号有效(建立连接后所有报文必须置
ACK=1
) - PSH:提示接收端立即将数据提交给应用层(如实时聊天)。
- RST:重置连接(用于异常终止或拒绝连接)。
- SYN:同步序列号(用于建立连接,见三次握手)。
- FIN:终止连接(用于四次挥手释放连接)。
-
TCP连接的过程(三次握手)
第一次: SYN(同步)
-
客户端发送一个TCP报文,包含:
- SYN=1(表示请求建立连接)
- 随机序列号(Seq=x) (防止历史重复连接)
-
客户端进入
SYN_SENT
状态。
第二次:SYN-ACK(同步-确认)
-
服务端收到SYN后,回复一个报文,包含:
- SYN=1 + ACK=1(确认客户端的SYN)
- 随机序列号(Seq=y)
- 确认号(Ack=x+1) (表示期望下次收到x+1的数据)
-
服务端进入
SYN_RCVD
状态。
第三次: ACK(确认)
-
客户端收到SYN-ACK后,发送最终确认报文:
- ACK=1
- 序列号(Seq=x+1)
- 确认号(Ack=y+1)
-
服务端收到后,双方进入
ESTABLISHED
状态,连接建立完成。
-
💡注意:只有要第三次握手才可以携带数据,前两次握手主要是客户端和服务器端之间的连接确认和同步序列号。
为什么是三次握手,而不是两次或四次?
你可以设想一下如果是两次:当客户端发送SYN报文之后由于网络堵塞,重新发送了SYN报文,那么服务器端先接收到的肯定是旧的SYN报文,其回复给客户端时,客户端发现期望的确认号不同,就会发送RST报文进行重新连接,但此时服务器已经和连接上了,这样就白白浪费了服务器资源。三次握手的话就刚刚好,客户端能确认服务端 "能接收请求" ,服务端能确认客户端 "能接收回应",双方都知情连接已建立。
-
发起HTTP请求 在完成tcp连接后,浏览器会正式发送HTTP请求读取文件.
- 请求报文的构造: 根据用户请求的URL设置:请求方法,请求头,请求体。 如:
makefile
GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0
Accept: text/html,application/xhtml+xml
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
6.服务器响应请求并返回结果 浏览器在收到请求后:
- 解析请求 解析请求方法、路径、HTTP版本。
- 处理请求 静态资源读取直接返回,动态资源调用后端代码,生成HTML或JSON数据。
- 构造HTTP响应 服务器返回HTTP响应报文。 例如:
js
HTTP/1.1 200 OK 状态行(状态码 + 状态描述)
<- 响应头
Content-Type: text/html; charset=utf-8 数据类型
Content-Length: 1234 数据长度
Set-Cookie: session_id=abc123 设置Cookie
->
响应体
<!DOCTYPE html>
<html>...</html>
7.浏览器接收并处理响应
(1) 解析响应
-
浏览器检查 状态码:
200
:成功,继续解析。301/302
:重定向,跳转新 URL。404
:资源不存在。500
:服务器错误。
-
解析 响应头:
Content-Type
:决定如何处理数据(如text/html
渲染为网页)。Set-Cookie
:存储 Cookie(用于会话管理)。
- 浏览器解析 HTML、构建 DOM、CSSOM、渲染页面
- 构建DOM树:词法分析然后解析成DOM树(dom tree),是由dom元素及属性节点组成,树的根是document对象
- 构建CSS规则树:生成CSS规则树(CSS Rule Tree)
- 构建render树:Web浏览器将DOM和CSSOM结合,并构建出渲染树(render tree)
- 布局(Layout):计算出每个节点在屏幕中的位置
- 绘制(Painting):即遍历render树,并使用UI后端层绘制每个节点
9.当所有数据传输完成后,客户端或服务器会主动关闭连接
💥此时触发 TCP 四次挥手:用于"优雅断开连接"💥
第一次挥手:A → B(FIN)
客户端 A: "我不发数据了,我这边结束发送。"
- A 发送一个带
FIN
标志位的 TCP 报文 - 表示:我想关闭我这边的发送功能
- 这时候 A 进入
FIN_WAIT_1
状态
2️⃣ 第二次挥手:B → A(ACK)
服务端 B: "好,我知道你不发了。"
- B 回复一个
ACK
报文,确认收到客户端的关闭请求 - A 收到这个 ACK 后,进入
FIN_WAIT_2
状态 - B 还可以继续发送数据(因为它的发送通道还开着)
3️⃣ 第三次挥手:B → A(FIN)
服务器 B: "我也发完了,准备关闭。"
- B 发送一个带
FIN
的 TCP 报文,请求关闭自己这边的发送通道 - B 进入
LAST_ACK
状态
4️⃣ 第四次挥手:A → B(ACK)
客户端 A: "收到,我这就断了。"
- A 回复一个
ACK
报文,表示确认 - 然后 A 进入
TIME_WAIT
状态,等待 2 倍的最大报文生存时间(MSL),以确保服务器接收到 ACK
最终:
- A 完全关闭连接
- B 收到 ACK 后,也关闭连接