前言
当我们在浏览器导航栏输入URL(网址)之后,按下回车enter就会跳转到这个页面。
从输入URL开始,后面都发生了什么?
让我们聚焦 “浏览器地址栏输入 URL 并回车” 这一日常操作,拆解背后从网络解析到页面渲染的全链路技术流程,覆盖 HTTP/HTTPS、TCP、DNS、浏览器缓存 / 渲染等核心知识点,这既是技术科普也是面试高频考点梳理。
一、URL解析
浏览器第一步会对输入的 URL 进行结构化拆解,明确请求的协议、目标服务器、资源位置等关键信息,这是整个网络流程的起点。
比如:https://www.example.com:8080/blog/article?id=123&page=2#comment-456
组成部分 | 示例内容 | 代表含义 |
协议 (Scheme) |
| 通信协议,这里是加密的 HTTPS(比 HTTP 更安全),也可以是 |
域名 (Domain) |
| 要访问的服务器 “名字”,相当于网络里的 “门牌号”,后续会通过 DNS 解析成 IP 地址 |
端口 (Port) |
| 服务器上的服务入口,HTTPS 默认是 |
路径 (Path) |
| 要访问的服务器资源路径,对应 “文件夹 / 文件” 结构,这里表示要访问博客的文章页面 |
查询参数 (Query) |
| 传给服务器的指令 / 数据,用 |
片段 (Fragment) |
| 页面内定位,不会发给服务器;这里表示页面加载后直接跳转到 id 为 |
✅提问
URL 中的片段(#)会发送给服务器吗?
答:不会,仅用于浏览器页面内定位,不参与网络请求。
二、浏览器检查缓存
URL 解析完成后,浏览器不会直接发起网络请求,而是会优先检查本地缓存(比如浏览器、电脑里的旧资源)。
✅目的:避免重复请求、提升页面加载速度、节省网络资源。
如果缓存里有最新的资源,直接用缓存,后面的步骤就省了;没命中缓存,才继续下一步。
✅提问
浏览器为什么要先检查缓存再发起网络请求?
答:减少重复网络请求,加快页面加载,节约网络资源。
三、DNS域名解析
当本地缓存未命中时,浏览器仅拥有域名,无法直接与服务器通信(网络通信依赖 IP 地址),因此需要通过 DNS 服务将域名转换为服务器的 IP 地址。
DNS(Domain Name System,域名系统)
所谓DNS域名查询解析就是域名 → IP地址
核心逻辑:DNS是解析是“就近查、优先用缓存”先查自己(浏览器)→ 电脑 → 家里 / 公司路由器 → 运营商 , 最后才查互联网的 “根服务器”。
✅目的:让 DNS 解析尽可能快,同时减轻根服务器的压力。是一套「尽量少跨网、优先用缓存」的优化策略。
✅提问
1. 问:DNS 解析的核心目的是什么?
答:把域名转换为服务器 IP 地址,实现网络通信。
2. 问:DNS 解析为什么采用「优先缓存、就近查询」策略?
答:加快解析速度,减轻根服务器压力。
四、建立TCP连接
当DNS解析完成,拿到IP地址的时候,浏览器会自动开始跟TCP建立连接(HTTP/HTTPS都基于TCP)
1.TCP三次握手
TCP 是可靠的面向连接的传输协议,必须通过「三次握手」确认双方能正常收发数据,才能建立连接。
- 在浏览器访问网站的场景下:
- 客户端:就是你本地电脑上运行的浏览器进程(比如 Chrome、Edge),它主动发起 TCP 连接请求。
- 服务端:就是你要访问的目标网站服务器(比如百度、淘宝的远程服务器),它被动等待并接受连接。
- 在TCP中,「客户端 / 服务端」是连接角色,不是固定的硬件:
- 客户端:主动发起连接的一方(谁先喊「我要连接」,谁就是客户端)
- 服务端:被动监听、接受连接的一方(谁在等别人来连,谁就是服务端)
✅三次握手的核心目的:确认客户端和服务端的「发送、接收」能力均正常。
- 第一次握手:客户端(浏览器)发 “请求连接” 的包,告诉服务器 “我要连你”。
- 第二次握手:服务器回复 “同意连接 + 确认收到”,告诉客户端 “我能接,也能发”。
- 第三次握手:客户端再回复 “确认”,双方连接正式建立。
✅提问
TCP 三次握手的核心目的是什么?
答:确认客户端和服务端的发送、接收能力都正常。
2.HTTPS场景:TLS握手(了解)
如果是https://协议,TCP 三次握手的连接建好后,会多一步 TLS 握手。
HTTPS 为实现数据加密传输,会在 TCP 三次握手完成后,立即进行 TLS 握手;并在 TCP 四次握手之前,关闭 TLS 加密会话。
也就是说HTTPS=在 HTTP 外面套一层 TLS,走 TCP 传输。
目的是:
① 验证服务器身份(防止中间人攻击)
② 协商加密规则(加密套件和会话密钥),保证后续数据传输不被窃听
③ 建立加密通道,后续所有 HTTP 数据都会被加密传输(HTTPS=HTTP+TLS 加密)
✅提问
HTTPS 比 HTTP 多了哪一步关键流程?作用是什么?
答:多了 TLS 握手,实现数据加密传输,防止窃听和中间人攻击。
五、浏览器发起请求(HTTP请求报文)
TCP(+TLS)连接建立好之后,浏览器会给服务器发送HTTP 请求,告诉服务器:我要访问哪个页面、我用的什么浏览器、需要什么格式的内容。
HTTPS 场景下该报文还会被 TLS 加密后再通过 TCP 传输,确保数据传输安全。
1. HTTP请求报文(Request)的组成
HTTP 请求报文整体由请求行、请求头、空行、请求体四部分组成,且空行是必备项,用于明确分隔请求头和请求体,即使没有请求体,空行也不能省略。
组成 | 通俗解释 |
请求行 | 核心指令:请求方法(GET/POST 为主)+ 资源路径 + HTTP 版本(比如 GET /blog/article HTTP/1.1) |
请求头 | 额外信息(比如告诉服务器 “我是 Chrome 浏览器”“我要 JSON 格式数据”),常用的有 Host(访问的域名)、User-Agent(客户端信息)、Cookie(登录信息) |
空行 | 分隔请求头和请求体,必须有 |
请求体 | 可选,POST 请求用(比如登录时传的账号密码),GET 请求一般没有 |
1.1 请求行
最开头一行,写三件事:用什么方式请求、要哪个资源、用的 HTTP 版本。即:请求方法 + URL + HTTP版本
例:GET /blog/article?id=123&page=2 HTTP/1.1
地址不包含"#"后面的锚点,那部分浏览器自己留着用
请求方法
- GET:获取资源
- POST:提交数据
- PUT:更新或创建指定资源
- DELETE:删除资源
- PATCH:部分更新
- HEAD:只获取响应头(不返回 body)
- OPTIONS:查询服务器支持的方法
1.2 请求头(Headers)
键值对,用来描述请求的额外信息,比如:类型、长度、认证
例:Authorization: Bearer xxx(带身份凭证,证明是合法用户)
Content-Type: application/json(声明数据格式,让服务器正确解析请求体)
常见的请求头(Request Headers)字段
字段 | 示例 | 说明 | 通俗理解 |
Host | example.com | 请求目标主机 | 告诉服务器你要访问哪一个网站。 |
User-Agent | Mozilla/5.0 | 客户端信息 | 告诉服务器你用的是什么客户端。 |
Accept | application/json | 希望返回的数据类型 | 告诉服务器我希望你返回什么格式的数据给我。 |
Authorization | Bearer token | 携带认证信息 | 身份凭证,告诉服务器 “我是谁,我已经登录了”。 |
Cookie | userId=100 | 携带 Cookie | 把服务器之前存在你浏览器里的小数据再带回给服务器。 |
Content-Type | application/json | 请求体格式 | 告诉服务器我传给你的请求体是什么格式。 |
Referer | https://google.com | 来源页面(防盗链) | 告诉服务器我是从哪个页面跳过来的。 |
这些请求头不是每个请求都必须带,而是浏览器 / 客户端根据场景自动决定要不要加,只有需要时才会出现,其中Host基本是必带的。
1.3 空行
必须有,用来隔开请求头和请求体,告诉服务器 “头信息结束了”
1.4 请求体(Body,可选)
用来放要传给服务器的数据、登录、发帖子这种 POST 请求,作为参数的账号密码 / 内容放这里
✅提问
1. 问:GET 请求和 POST 请求在请求体上有什么区别?
答:GET 一般无请求体;POST 有请求体,用于提交账号密码等数据。
2. 问:HTTP 请求报文中的空行可以省略吗?
答:不可以,必须有,用于分隔请求头和请求体。
2. 浏览器给example.com的服务器发了一条消息:
POST /api/login HTTP/1.1 Host: example.com User-Agent: Mozilla/5.0 Content-Type: application/json Content-Length: 35 {"username": "Ryne", "password": "123"}通信规则:用 POST 请求方法,调用/api/login登录接口,基于 HTTP/1.1 协议,向example.com服务器发起请求。
请求头说明:包含 Host、User-Agent、Content-Type、Content-Length 等信息,给服务器补充:请求的目标是
example.com网站、客户端信息(告知服务器本次请求来自浏览器)、数据格式(JSON 格式,需按 JSON 规则解析后续提交的业务数据)和请求体的字节长度为 35。空行分隔:请求头和请求体之间的空行,是 HTTP 协议强制要求,用来划分请求头和请求体的边界。
核心逻辑:通过 JSON 格式的请求体{"username": "Ryne", "password": "123"},向服务器提交用户的登录账号和密码,服务器校验后返回登录结果。
六、服务器响应HTTP请求(HTTP响应报文)
经过TCP传输服务器收到浏览器发送的 HTTP 请求后,会解析请求、执行业务逻辑(如验证登录账号密码),处理完成后返回HTTP 响应报文,告知浏览器对于该请求的处理结果。
HTTPS 场景下该报文同样会经 TLS 加密后传输,浏览器接收后先解密再解析。
1. HTTP响应报文(Response)的组成
组成 | 通俗解释 |
状态行 | 处理结果:HTTP 版本 + 状态码 + 描述(比如 200 OK 表示成功,404 Not Found 表示资源不存在) |
响应头 | 服务器的额外信息(比如返回内容是 HTML、设置 Cookie) |
空行 | 分隔响应头和响应体,必须有 |
响应体 | 核心内容:传统网站返回完整 HTML,Vue/React 项目只返回 “空骨架”(后续加载 JS 填内容) |
1.1 状态行
表示请求处理的结果(HTTP版本 + 状态码 + 状态描述)
示例:HTTP/1.1 200 OKHTTP/1.1 404 Not Found
状态码 (记分类就行)
分类 | 范围 | 含义 | 常见示例 |
1xx | 100–199 | 信息性,表示请求已接收继续处理 | |
2xx | 200–299 | 成功 | 200(请求成功) |
3xx | 300–399 | 重定向 | 301(永久跳新地址)、302 (临时跳转)、304(用本地缓存) |
4xx | 400–499 | 客户端错误 | 401(没登录)、404(资源不存在) |
5xx | 500–599 | 服务器错误 | 500(服务器出问题) |
✅提问
问:重定向类(3xx)是什么?
答:请求资源的地址有问题,是「重定向 / 缓存提示」,属于正常的业务跳转,服务器没出错、浏览器也没出错。
如果是301,就是说原来的旧地址不用了,服务器会将返回一个新地址;浏览器会记住这个跳转,下次再输旧网址,会直接访问新地址,不再问服务器。
如果是302,旧地址还能用,暂时让你去旧地址还能用、只是暂时让你去别的地方,比如未登录访问个人中心,服务器临时让你跳登录页,下次再访问旧地址,依旧会先请求服务器,不会直接跳过。
如果是304,它和 “地址更换” 没关系,只是服务器说:你本地缓存的文件还是最新的,别重新下载了,直接用本地的
1.2 响应头(Headers)
用于传递服务器关于响应的元数据信息等
示例:
Content-Type: application/jsonSet-Cookie: sessionid=abc123Cache-Control: max-age=3600
常见响应头(Response Headers)
字段 | 示例 | 说明 |
Content-Type | text/html | 返回内容类型 |
Content-Length | 1024 | 返回体长度 |
Cache-Control | max-age=3600 | 缓存策略 |
Set-Cookie | session=abc123 | 设置 Cookie |
Access-Control-Allow-Origin | * | 允许跨域访问 |
ETag | "a1b2c3" | 内容唯一标识(缓存验证) |
特殊头部:
- CORS 跨域相关:
Access-Control-Allow-Origin - 缓存控制:
ETag、Last-Modified、(强缓存,有效期内完全不发请求,直接读缓存,性能最优、零网络开销)
Cache-Control、Expires(协商缓存,每次都发请求,验证后决定是否读缓存,精准控制、避免过期资源)
1.3 空行
必须有,用来隔开响应头和响应体,告诉服务器 “头信息结束了”
1.4 响应体
不同于api接口请求,在导航栏输入URL的这种场景下,HTTP响应报文的响应体是HTML,而这个HTML会分为两种情况:
- 传统的网站:服务器直接把整个页面内容全部拼好返回给你——文字、列表、图片路径、甚至表格数据全都写在 HTML 里,浏览器拿到直接渲染,就能看到完整页面
- 现代Vue/React前后端分离网站:返回的是HTML的完整骨架,内容等JS加载完填充进去
而决定响应体返回的是传统HTML、Vue、React是由部署在服务器的前端静态文件,当浏览器访问URL时,服务器会直接读取这个部署好的index.html文件,原封不动的返回给浏览器。
2. 最终浏览器收到响应报文的示例
2.1 传统html
# 1. 状态行(固定第一行) HTTP/1.1 200 OK # 2. 响应头(键值对) Server: nginx/1.21.6 Content-Type: text/html; charset=utf-8 Content-Length: 320 Cache-Control: max-age=3600 # 3. 空行(必备分隔符) # 4. 响应体(完整HTML页面,渲染的核心数据) <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>博客页面</title> </head> <body> <h1>我的博客</h1> <p>这是文章内容</p> </body> </html>通信规则:返回 200 成功响应,服务器用 Nginx,内容是 UTF-8 编码的 HTML。
缓存策略:max-age=3600表示缓存 1 小时,提升重复访问的加载速度。
完整内容:HTML 里直接写满了页面所有文字、标签,是完整的页面代码。
核心逻辑:服务器直接把完整页面一次性发给浏览器,浏览器拿到后直接渲染显示,无需额外下载 JS。
2.2 Vue版本
# 1. 状态行 HTTP/1.1 200 OK # 2. 响应头 Server: nginx/1.21.6 Content-Type: text/html; charset=utf-8 Content-Length: 280 Cache-Control: no-cache # 3. 必备空行 # 4. 响应体:Vue 完整空白骨架HTML <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Vue 项目</title> </head> <body> <!-- Vue 根节点,内容由JS动态渲染 --> <div id="app"></div> <!-- 加载Vue核心JS --> <script src="/js/app.js"></script> </body> </html>通信规则:返回200 成功响应,服务器用 Nginx,内容是 UTF-8 编码的 HTML。
缓存策略:no-cache 表示不缓存,确保用户每次都能拿到最新的前端代码。
空壳骨架:HTML 里只有一个空的 <div id="app"> 容器,没有任何页面文字,它只是一个占位符。
核心逻辑:通过 <script src="/js/app.js"> 让浏览器去下载 Vue 核心代码。代码加载完成后,会自动把动态内容渲染到 <div id="app"> 这个盒子里。
2.3 React版本
# 1. 状态行 HTTP/1.1 200 OK # 2. 响应头 Server: nginx/1.21.6 Content-Type: text/html; charset=utf-8 Content-Length: 290 Cache-Control: no-cache # 3. 必备空行 # 4. 响应体:React 完整空白骨架HTML <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>React 项目</title> </head> <body> <!-- React 根节点,内容由JS动态渲染 --> <div id="root"></div> <!-- 加载React核心JS --> <script src="/js/main.js"></script> </body> </html>通信规则:返回 200 成功响应,服务器用 Nginx,内容是 UTF-8 编码的 HTML。
缓存策略:no-cache表示不缓存,确保用户每次都能拿到最新的前端代码。
空壳骨架:HTML 里只有一个空的<div id="root">容器,没有任何页面文字,它只是一个占位符。
核心逻辑:通过<script src="/js/main.js">让浏览器去下载 React 核心代码。代码加载完成后,会自动把动态内容渲染到<div id="root">这个盒子里。
七、浏览器渲染
服务器返回完整的HTTP 响应报文后,浏览器会先解析报文结构,通过空行分隔响应头和响应体,提取响应体中的完整 HTML 文件(传统页面 / Vue/React 骨架),以此为核心原材料,执行固定的渲染流程,最终将页面展示在屏幕上。
传统网站: HTML 响应体包含完整页面内容,直接解析、渲染,完成后就能看到页面;
Vue/React 项目:框架的 HTML 响应体仅为空白骨架(如<div id="app"></div>),解析、渲染完成后需加载 JS 代码,由 JS 动态生成页面内容并完成二次渲染。
✅ 核心:最终把代码转换成咱们能看的可视化页面。
完整流程图如下:
✅提问
1. 问:图层的分层、合并是什么?为什么有这一步?
答:浏览器会根据页面的情况将绘制好的内容拆分为多个独立的渲染图层,完成布局和绘制后会按照特定的堆叠顺序将这些图层叠加、合并成一张完整的图像,并最终显示在屏幕上。
拆分图层可以让浏览器单独处理需要重新渲染的部分,提高性能;视频、3D变换......会在独立的图层、GPU可以更加高效的合成到画面上,保证画面不卡顿。
2. 问:现代 Vue/React 项目的 HTML 响应体和传统网站有什么不同?
答:Vue/React 仅返回空白骨架,内容由 JS 动态填充;传统网站返回完整页面内容。
八、TCP断开连接
页面加载完后,TCP并不会立即断开连接(HTTP/1.1默认持久连接 (Keep-Alive),支持多个请求复用同一个 TCP 连接),因为可能后续还有网络请求。只有满足以下任一条件,才会断开:
- 连接空闲超时:页面加载完成后,闲置几十秒没有任何请求
- 服务器主动关闭:服务器设置了最大连接时间 / 次数
- 手动关闭:你关闭网页、关闭浏览器
- 所有请求彻底结束:没有任何资源需要加载了
否则TCP会一直连接并保持空闲(等待可能的新请求)
✅提问
为什么TCP不会立即断开?
答:页面可能还需要加载后续资源(图片、接口请求、JS 异步数据);TCP 建立(三次握手)+ 断开(四次挥手)很消耗性能,保持连接能避免重复握手,提升速度
HTTPS 场景:TLS 挥手(了解)
按照 TLS 规范:数据传输完成 → 先进行 TLS 挥手 → 再执行 TCP 四次挥手
- TLS 挥手:双方发送
close_notify告警,安全结束加密会话,避免被判定为截断攻击 - 实际生产环境(Nginx、浏览器等):为提升性能,通常省略 TLS 挥手,数据传输完成后直接发起 TCP 四次挥手
数据传输完成后,TCP 连接需要通过「四次挥手」安全断开(因为 TCP 是全双工,双方都要关闭各自的发送通道)
TCP四次挥手(核心记 “全双工,分步关闭”)
TCP 是双向传输(全双工),关闭时要分别关闭双方的发送通道,所以需要 4 步:
- 客户端说 “我没数据要发了,关我的发送通道”;
- 服务器回复 “收到,我这边准备关”;
- 服务器说 “我也没数据了,关我的发送通道”;
- 客户端回复 “收到,确认关闭”,等待片刻后连接彻底断开。
当TCP彻底断开连接,标志着从输入URL开始的这个网络通信流程正式结束。
(HTTPS 场景下,会先关 TLS 加密会话,再走 TCP 四次挥手,了解即可)
✅提问
1. 问:为什么建立连接是三次握手,关闭连接却是四次挥手?
答:三次握手:服务端可以把 SYN(同意连接) 和 ACK(确认请求) 合并成一个包发送,所以少一次。
四次挥手:服务端收到客户端的 FIN 后,只能先回复 ACK 确认;等自己数据也发完了,才能再发 FIN 关闭自己的通道,两个步骤无法合并,因此需要四次。
问:TCP 四次挥手的核心原因是什么?
答:TCP 是全双工,需分别关闭双方的发送通道,分步断开更安全。
总结
从输入 URL 到页面显示,核心流程就 8 步:
URL解析 → 检查本地缓存 → DNS域名解析 → TCP连接 → 浏览器发出HTTP请求 → 服务器返回响应 → 浏览器渲染页面 → 满足条件后TCP断开连接
✅需要掌握的:
- 浏览器查询缓存的完整过程;
- 缓存和 DNS 解析的共同优化策略是 “优先本地,提升速度”;
- HTTP请求 / 响应报文的核心组成,常见的请求头、响应头字段;
- HTTPS 相比 HTTP 多了什么关键步骤?
- TCP三次握手建连接、四次挥手断连接的流程与目的;
- 浏览器渲染的核心逻辑和过程。
整个过程其实就是计网课上学的 “应用层(HTTP)→ 传输层(TCP)→ 网络层(IP/DNS)” 的实际落地,把知识点串起来就很好理解啦~