在发送 http 请求报文时,host 是必要的吗
在发送 HTTP 请求报文时,Host 头字段是必要的(具体取决于 HTTP 协议版本和应用场景)。以下是详细解释:
1. HTTP/1.1 及更高版本:必须包含 Host 头
- RFC 规范要求:根据 HTTP/1.1 协议(RFC 7230),客户端必须在请求中包含
Host头字段,否则服务器会返回400 Bad Request错误。 - 用途:
Host头 服务器通过此字段区分不同网站(尤其是当单个 IP 托管多个域名时,即“虚拟主机”)。例如:GET /index.html HTTP/1.1 Host: www.example.com # 服务器通过此字段区分不同网站 - 示例场景:
- 如果通过 IP 直接访问服务器(如
http://192.168.1.1),仍需显式指定Host头。 - 若省略
Host头,服务器无法确定客户端请求的是哪个域名的资源。
- 如果通过 IP 直接访问服务器(如
2. HTTP/1.0:Host 头非必需
- 在早期的 HTTP/1.0 中,
Host头不是强制要求的,因为当时单 IP 对应单域名的场景更常见。 - 现状:由于 HTTP/1.0 已过时,现代服务器和客户端普遍遵循 HTTP/1.1 或更高版本规范。
实际开发建议:始终在 HTTP/1.1 及以上版本的请求中包含 Host 头,以确保兼容性和正确路由。
http1.1与http2有什么不同 ⭐️⭐️ (重点)
http1.1
- 持久连接:HTTP1.0 中,每次请求 - 响应完成后,连接就会关闭,而 HTTP1.1 支持持久连接,只要客户端/服务端中任意一端没有明确指出断开TCP连接,就一直保持连接。减少了建立和关闭连接的开销,提高了传输效率
- 管线化:在一次 TCP 连接中可以传输多个 HTTP 请求和响应,而不用等待前一个请求的响应回来再发下一个,提高了传输效率 。但服务器仍需按顺序处理和响应请求。比如在浏览网页加载多个资源时,客户端能连续发出资源请求。
- 分块传输编码:当服务器不知道响应数据的长度时,可使用分块传输编码,将数据分成多个块进行传输,增强了传输的灵活性。断点续传
- 缓存处理改进:引入更多缓存相关的指令,如
Cache-Control,能更精准地控制页面缓存,提高缓存的有效性和安全性。 - Host 头字段:支持在同一个
IP 地址和端口号上部署多个网站,通过Host头字段来区分不同的站点
http2
- 1、二进制传输
- 2、多路复用
- 3、头部压缩
- 4、服务器推送
- 5、 流优先级
- 6、更安全
HTTP/2(2015 年发布) 在 HTTP/1.1(1997 年发布)的基础上进行了多项改进,主要目标是提升性能、降低延迟
1. 二进制协议 vs 文本协议
-
HTTP/1.1:
- 文本格式:请求和响应以纯文本(如
GET /index.html HTTP/1.1)传输,解析复杂且易出错。
- 文本格式:请求和响应以纯文本(如
-
HTTP/2:
- 二进制分帧:将数据分解为更小的二进制帧(如 HEADERS 帧、DATA 帧),传输效率更高,解析更简单。
2. 多路复用(Multiplexing)
-
HTTP/1.1:
- 队头阻塞(Head-of-Line Blocking):每个 TCP 连接在同一时间只能处理一个请求(虽然浏览器支持 6-8 个并行连接,但资源竞争仍会导致延迟)。
- 低效并行:大量请求需要多个 TCP 连接,增加了资源开销。
-
HTTP/2:
- 单连接多流:通过二进制分帧层,允许在
单个 TCP 连接上并行传输多个请求和响应(称为“流”)。 - 消除队头阻塞:
请求和响应 交替传输,互不影响。
- 单连接多流:通过二进制分帧层,允许在
3. 头部压缩(Header Compression)
-
HTTP/1.1:
- 重复传输头部:每次请求都携带完整的头部(如 Cookie、User-Agent),冗余数据浪费带宽。
-
HTTP/2:
- HPACK 压缩算法:使用静态字典(预定义常用字段)和动态字典(记录本次连接的字段)压缩头部,减少传输体积。
- 典型压缩率:头部大小可减少 50%~90%。
4. 服务器推送(Server Push)
-
HTTP/1.1:
- 被动响应:服务器只能返回客户端显式请求的资源。
-
HTTP/2:
- 主动推送:服务器可预测客户端需求,提前推送相关资源(如 CSS、JS 文件),减少往返延迟。
- 示例:当客户端请求
index.html时,服务器可同时推送style.css。
5. 流优先级(Stream Prioritization)
-
HTTP/1.1:
- 无优先级控制:资源加载顺序由浏览器猜测,可能导致关键资源(如 CSS)延迟加载。
-
HTTP/2:
- 优先级标记:客户端可为每个流设置权重和依赖关系,确保关键资源优先传输(如优先加载 HTML 骨架,再加载图片)。
6. 安全性(Security)
-
HTTP/1.1:
- 明文传输:默认不加密,需通过 HTTPS(HTTP over TLS)实现安全通信。
-
HTTP/2:
- 不强制加密:协议本身未要求加密,但主流浏览器(如 Chrome、Firefox)仅支持基于 HTTPS 的 HTTP/2。
- 实际强制加密:实践中 HTTP/2 几乎总是与 TLS 结合使用。
实际影响
- 加载速度提升:HTTP/2 显著减少延迟,尤其对高延迟网络(如移动端)效果明显。
- 资源利用率优化:减少 TCP 连接数和头部开销,降低服务器压力。
- 兼容性:HTTP/2 完全兼容 HTTP/1.1 的语义(如方法、状态码),无需修改应用层逻辑。
注意事项
- 旧设备支持:部分老旧代理或防火墙可能不支持 HTTP/2 的二进制协议,需降级到 HTTP/1.1。
- 服务器配置:需 Web 服务器(如 Nginx、Apache)和 CDN 支持 HTTP/2。
- HTTPS 成本:强制加密需配置 TLS 证书,可能增加运维成本。
总结:HTTP/2 通过多路复用、头部压缩、服务器推送等机制,解决了 HTTP/1.1 的性能瓶颈,是构建现代高性能 Web 应用的基石。
简单讲解一下http2的多路复用 ⭐️
即单个 TCP 连接上并行传输多个请求和响应
HTTP/2 的多路复用(Multiplexing) ,目的是解决 HTTP/1.x 的队头阻塞问题,显著提升网络传输效率。
1. HTTP/1.1 的痛点:队头阻塞
在 HTTP/1.1 中:
- 客户端和服务器通过一个 TCP 连接
按顺序发送请求和响应。 - 如果某个请求耗时较长(比如下载一个大文件),后续请求必须排队等待,这就是队头阻塞。
- 虽然可以通过并发多个 TCP 连接缓解问题(比如浏览器默认开6个连接),但会消耗更多资源,且难以彻底解决。
2. HTTP/2 的解决方案:多路复用
HTTP/2 允许在同一个 TCP 连接上,并行传输多个请求和响应,且彼此互不阻塞。实现原理如下:
- 二进制分帧层:HTTP/2 将请求和响应拆分为更小的二进制帧(Frame),每个帧 携带一个唯一标识(Stream ID),表示它属于哪个请求/响应。
- 并行传输:所有帧通过同一个 TCP 连接发送,不同 Stream ID 的帧可以交替传输,服务器和客户端会根据 Stream ID 重新组装成完整的请求/响应。
举个例子:
假设浏览器需要加载一个页面,包含 HTML、CSS、图片等资源:
- HTTP/1.1:需要按顺序逐个请求,或者开多个 TCP 连接并行请求(资源浪费)。
- HTTP/2:在同一个连接中,所有资源请求的帧混合传输,无需等待前一个完成。
3. 多路复用的优势
- 消除队头阻塞:慢请求不会阻塞其他请求。
- 减少连接数:无需创建多个 TCP 连接,降低服务器和客户端资源消耗。
4. 对比 HTTP/1.1 的管道化(Pipelining)
HTTP/1.1 曾尝试通过管道化(一次性发送多个请求)优化性能,但存在严重缺陷:
- 响应必须按请求顺序返回(依然有队头阻塞)。
- 部分服务器不支持或实现不完善。
总结
HTTP/2 的多路复用通过 二进制分帧 和 流标识(Stream ID),实现了同一连接上的高效并发,解决了 HTTP/1.x 的性能瓶颈,是现代化 Web 高效传输的基石。
介绍一下http2.0
什么是HTTP2.0
1、是HTTP协议的第二个主要版本,主要基于SPDY协议,大幅度提高了web性能,降低延迟。
SPDY是Speedy的昵音,意为“更快”。它是Google开发的基于TCP协议的应用层协议。目标是优化HTTP协议的性能,通过压缩、多路复用和优先级等技术,缩短网页的加载时间并提高安全性。SPDY协议的核心思想是尽量减少TCP连接数。SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强
HTTP2.0特点
1、二进制传输
文本的表现形式有多样性,健壮性考虑,HTTP2.0中所有加强性能的核心是二进制传输,在HTTP1.x中,我们是通过文本的方式传输数据。
基于文本的方式传输数据存在很多缺陷,文本的表现形式有多样性,因此要做到健壮性考虑的场景必然有很多,但是二进制则不同,只有0和1的组合,因此选择了二进制传输,实现方便且健壮
在HTTP2.0中引入了新的编码机制,所有传输的数据都会被分割,并采用二进制格式编码。 为了保证HTTP不受影响,那就需要在应用层(HTTP2.0)和传输层(TCP or UDP)之间增加一个二进制分帧层。在二进制分帧层上,HTTP2.0会将所有传输的信息分为更小的消息和帧,并采用二进制格式编码,其中HTTP1.x的首部信息会被封装到Headers帧,而Request Body则封装到Data帧。
2、多路复用
即单个 TCP 连接上并行传输多个请求和响应
在HTTP1.0中,我们经常会使用到雪碧图、使用多个域名等方式来进行优化,都是因为浏览器限制了同一个域名下的请求数量,当页面需要请求很多资源的时候,队头阻塞(Head of line blocking)会导致在达到最大请求时,资源需要等待其他资源请求完成后才能继续发送。 HTTP2.0中,有两个概念非常重要:帧(frame)和流(stream)。 帧是最小的数据单位,每个帧会标识出该帧属于哪个流,流是多个帧组成的数据流。 所谓多路复用,即在一个TCP连接中存在多个流,即可以同时发送多个请求,对端可以通过帧中的表示知道该帧属于哪个请求。在客户端,这些帧乱序发送,到对端后再根据每个帧首部的流标识符重新组装。通过该技术,可以避免HTTP旧版本的队头阻塞问题,极大提高传输性能。
3、Header压缩
使用文本的形式传输header,在header中携带cookie的话,开销大
在HTTP1.1中,我们使用文本的形式传输header,在header中携带cookie的话,每次都需要重复传输几百到几千的字节,这着实是一笔不小的开销。 在HTTP2.0中,我们使用了HPACK(HTTP2头部压缩算法)压缩格式对传输的header进行编码,减少了header的大小。并在两端维护了索引表,用于记录出现过的header,后面在传输过程中就可以传输已经记录过的header的键名,对端收到数据后就可以通过键名找到对应的值。
4、服务器Push
在HTTP2.0中,服务端可以在客户端某个请求后,主动推送其他资源。
可以想象一下,某些资源客户端是一定会请求的,这时就可以采取服务端push的技术,提前给客户端推送必要的资源,就可以相对减少一点延迟时间。在浏览器兼容的情况下也可以使用prefetch。
5、更安全
HTTP2.0使用了tls的拓展ALPN做为协议升级,除此之外,HTTP2.0对tls的安全性做了近一步加强,通过黑名单机制禁用了几百种不再安全的加密算法。
随着 http2 的发展,前端性能优化中的哪些传统方案可以被替代
随着 HTTP/2 的普及,其核心特性(如多路复用、二进制分帧、服务器推送等)显著改变了前端性能优化的策略。以下是一些可被替代的传统优化方案及其替代思路:
1. 资源合并(文件合并与雪碧图)
- 传统方案:合并多个 CSS/JS 文件为单个文件,或使用雪碧图(CSS Sprites)减少 HTTP 请求次数。
- HTTP/2 的替代:
- 多路复用:小文件通过单一连接并行传输,合并文件反而可能降低缓存效率(如某部分内容变更需重新下载整个文件)。
- 雪碧图:HTTP/2 下,独立图片请求更高效,
雪碧图维护成本高且不利于按需加载,可改用单独图片或 WebP/AVIF 格式优化体积。
2. 内联资源(如 Base64 图片、行内 CSS/JS)
- 传统方案:
将资源(如图片转为 Base64、CSS/JS 内联到 HTML)以减少请求次数。 - HTTP/2 的替代:HTTP/2 对小文件请求更高效,内联资源会增加 HTML 体积,影响首屏渲染速度和缓存策略。建议将资源外链,利用 HTTP/2 的多路复用特性。
3. 管线化(HTTP Pipelining)优化
- 传统方案:HTTP/1.1 的管道化允许在同一个连接上发送多个请求,但响应必须按顺序返回,实际应用受限且易受队头阻塞影响。
- HTTP/2 的替代:HTTP/2 的二进制分帧和流(Stream)机制天然支持乱序传输,彻底解决队头阻塞问题,无需手动优化请求顺序。
4. 手动资源预加载
- 传统方案:通过
<link rel="preload">或 JavaScript 预加载关键资源。 - HTTP/2 的替代:利用 服务器推送(Server Push),服务器可主动推送与当前请求相关的资源(如 CSS、JS),
减少客户端主动请求的延迟。例如,Nginx 可通过Link头部实现推送。
总结
HTTP/2 通过协议层的改进,简化了许多 HTTP/1.1 时代的“妥协式”优化方案。开发者应摒弃过度合并、分片等传统手段,转而利用多路复用、服务器推送等特性,结合现代前端工程化工具(如 Webpack 按需加载、Vite 原生 ESM)实现更高效的性能优化。
HTTP/2 时代的新优化方向
- 优先级与流量控制:通过设置资源优先级(如 CSS > 图片),确保关键资源优先加载。
- Server Push 的合理使用:避免过度推送导致带宽浪费,需结合实际业务场景动态调整。
- TLS 优化:HTTP/2 通常与 HTTPS 绑定,需优化 TLS 握手(如 Session Resumption、TLS 1.3)以减少延迟。
http1.1是如何复用tcp连接
在 HTTP/1.1 中,TCP 连接的复用是通过持久连接实现的
1. HTTP/1.1 的持久连接(Keep-Alive)
- 默认行为:HTTP/1.1 默认启用持久连接(无需显式添加
Connection: keep-alive头字段)。 - 工作原理:
- 客户端和服务器建立一次 TCP 连接后,可以在该连接上发送多个 HTTP 请求/响应(
按顺序处理)。 - 连接不会在每次请求后立即关闭,而是**
保持打开状态,直到超时或主动关闭**。
- 客户端和服务器建立一次 TCP 连接后,可以在该连接上发送多个 HTTP 请求/响应(
- 示例流程:
# 第一次请求 GET /page1.html HTTP/1.1 Host: example.com # 服务器响应后,同一 TCP 连接继续复用: GET /page2.html HTTP/1.1 Host: example.com
HTTP/3的核心改进是什么?
- 基于QUIC协议 :在UDP上实现可靠传输,解决TCP队头阻塞。
- 快速握手 :0-RTT或1-RTT建立连接(减少延迟)。
- 连接迁移 :网络切换时(如WiFi转4G)保持连接。
http2.0/http3.0
常见考点
在前端面试中,HTTP/2 与 HTTP/3 的考察,主要围绕它们对页面加载性能的影响、核心特性对比、底层协议差异以及使用中的优劣权衡。
一、背景与版本演进
| 协议版本 | 年份 | 核心变化 |
|---|---|---|
| HTTP/1.1 | 1997 | 长连接(Keep-Alive)、管道化(但有队头阻塞) |
| HTTP/2 | 2015 | 二进制帧、多路复用、头部压缩、服务端推送 |
| HTTP/3 | 2022 | 基于 QUIC 替代 TCP,进一步解决队头阻塞,提升可靠性 |
二、HTTP/1.1 vs HTTP/2 vs HTTP/3 对比
| 特性 | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| 传输协议 | TCP | TCP | QUIC(基于 UDP) |
| 多路复用 | ❌ 队头阻塞 | ✅ 同一连接并行传输 | ✅ 无队头阻塞 |
| 首部压缩 | ❌ 无压缩 | ✅ HPACK | ✅ QPACK(防止队头阻塞) |
| Server Push | ❌ 不支持 | ✅ 支持 | ❌ 已废弃(实践效果差) |
| 建连速度 | 普通 TCP + TLS | TCP + TLS | ✅ 快速握手(1-RTT) |
| 丢包处理 | 影响所有流 | 影响所有流 | ✅ 仅影响单一流 |
| 中间设备兼容性 | 高 | 高 | ⚠️ UDP 可能被阻断 |
四、HTTP/3 的面试考察点
1. QUIC 协议(核心考点)
- 基于 UDP,支持多路复用,无需三次握手
- 加密集成在协议中(类似 TLS 1.3),连接建立更快
- 无队头阻塞:丢包不会影响所有请求,只影响对应流
2. QPACK 头部压缩算法
- 类似 HPACK,但解决了在多路复用中可能造成阻塞的问题
3. 快速恢复连接
- QUIC 支持 0-RTT 连接恢复,提升访问速度(尤其移动网络)
4. 防中间人攻击
- QUIC 所有内容默认加密,提升安全性
- 中间代理设备无法篡改请求内容
5. 使用上的挑战
- 部分网络设备不支持 UDP 或限制端口
- 浏览器和 CDN 需明确支持 HTTP/3(如 Chrome、Cloudflare 支持)
五、面试常见问题示例
| 问题 | 涉及考点 |
|---|---|
| HTTP/2 和 HTTP/1.1 有哪些不同? | 多路复用、帧机制、压缩、Server Push |
| HTTP/3 为什么使用 QUIC? | 解决 TCP 队头阻塞、连接快、抗丢包 |
| QUIC 相比 TCP 有什么优势? | 基于 UDP、多路复用、低延迟连接 |
| 为什么说 HTTP/2 仍然存在队头阻塞? | 底层仍基于 TCP,TCP 丢包影响整条流 |
| HTTP/3 是否取代 HTTP/2? | 正在推广中,但需服务端、客户端、CDN 三方支持 |
| Server Push 有什么问题? | 资源浪费、缓存难控、已废弃 |
六、实际使用和优化建议(工程落地)
- 启用 HTTP/2/3 需后端或 CDN 支持(例如在 Nginx、Cloudflare 开启)
- 前端不需要做太多改动,但要合理使用 preload 代替 server push
- 对图片、CSS、JS 等静态资源分发,HTTP/2 提升明显
- 对动态资源或高延迟网络访问,HTTP/3 的优势更大
七、总结
- 为什么 HTTP/2 引入多路复用?→ 解决 HTTP/1.1 队头阻塞
- 为什么 HTTP/3 不再使用 TCP?→ TCP 层面的队头阻塞无法解决
- 为什么 QUIC 比 TCP 快?→ 更快建连、单流丢包不影响整体
- 为什么 Server Push 被废弃?→ 实际效果不佳,控制困难
关联面试题
为什么说 HTTP/2 仍然存在队头阻塞?
HTTP/2 解决了 HTTP/1.1 的队头阻塞(请求级阻塞) ,但仍存在 TCP 层的队头阻塞,核心原因如下:
- HTTP/2 的改进它基于单个 TCP 连接实现多路复用,多个请求 / 响应可在同一连接上并行传输,不会因为一个请求阻塞导致后续请求排队,解决了 HTTP 应用层的队头阻塞。
- TCP 层的队头阻塞无法避免TCP 是可靠的字节流协议,数据传输以有序报文段的形式进行。如果某一段报文丢失或出错,即使后续报文已到达,也必须等待丢失的报文重传并确认后,才能将数据交给应用层(HTTP/2)。此时,HTTP/2 多路复用的所有流都会被阻塞,这就是 TCP 层的队头阻塞。
简单说:HTTP/2 解决了应用层的队头阻塞,但绕不开 TCP 协议本身的有序传输特性,因此仍存在底层的队头阻塞。
http2.0 服务端推送常见考点
HTTP/2 的服务端推送(Server Push)是一个重要但实际使用率较低的特性。它允许服务器在客户端还未明确请求资源时,主动将资源“推送”给客户端,用于提前加载关键资源以加快页面渲染。
虽然 HTTP/3 取消了该功能,但面试中仍会从“机制原理 + 使用场景 + 弊端与替代方案”多个角度进行考察。
一、基础原理考察
1. 什么是 HTTP/2 的 Server Push?
- 客户端发起一个主请求(如 HTML 页面)时,服务器可以在响应之前或同时,主动推送其它关联资源(如 CSS/JS)。
- 客户端无需显式请求这些资源,它会缓存或使用服务端推送的内容。
2. 工作机制
- 浏览器发起请求 → 服务器通过
PUSH_PROMISE帧声明要推送哪些资源 - 客户端接收到声明后,可选择接受或拒绝(缓存中已有则拒绝)
- 服务器随后发送资源 → 客户端使用或缓存
二、使用场景考察
- 页面关键资源预加载:如首页 HTML 加载时提前推送 CSS/JS
- 提升首屏加载速度:配合缓存策略使用,在访问频繁页面中生效显著
- 避免额外 RTT(请求-响应延迟)
三、配置与实现考察
1. Nginx 示例:
http2_push /styles.css;
http2_push /main.js;
2. Express 示例(使用 Link 头):
res.set('Link', '</style.css>; rel=preload; as=style');
3. HTTP 响应头方式:
Link: </styles.css>; rel=preload; as=style
注意:这种方式只在支持 HTTP/2 Server Push 的服务端生效。
四、常见面试考点
| 问题 | 回答要点 |
|---|---|
| HTTP/2 的 Server Push 原理? | 主动发送 PUSH_PROMISE,减少 RTT,预加载资源 |
| 与浏览器 preload 的区别? | preload 是客户端主动告知,Server Push 是服务端主动 |
| Server Push 如何实现? | 使用 Link 头或服务器配置,依赖 HTTP/2 |
| Server Push 有哪些缺陷? | 资源可能已缓存、浪费带宽、无法精准控制推送时机 |
| Server Push 为什么在 HTTP/3 中被废弃? | 使用率低、不稳定、难以优化资源调度 |
| 如何替代 Server Push? | 使用 preload、prefetch、Service Worker 缓存等 |
五、缺陷与注意点考察
- 缓存浪费问题:如果客户端已经缓存资源,服务端仍然推送 → 浪费带宽
- 调度不可控:无法像 JS
preload那样设置优先级、资源时机 - 对 CDN 不友好:CDN 无法判断是否应推送资源
- 浏览器支持差异:部分浏览器已不再积极支持该特性
- 现代替代方案更可控:如
<link rel="preload">、lazy loading
http优化策略 ⭐️⭐️重点
- 一、减少请求数量
- 二、减少响应体积
- 三、提升协议层
以下是针对 HTTP 协议性能优化的常见策略,从协议特性到工程实践的全方位总结:
一、减少请求数量
-
资源合并
- CSS/JS 文件合并:减少 HTTP 请求次数(适用于 HTTP/1.1,HTTP/2 中无需过度合并)。
- 雪碧图(CSS Sprites):将多个小图标合并为一张大图,通过
background-position定位。
-
缓存策略优化
- 强缓存(
Cache-Control,Expires)与协商缓存(ETag,Last-Modified)合理配置,避免重复请求。
- 强缓存(
二、减少响应体积
-
压缩算法
- Gzip/Brotli 压缩:对文本类资源(HTML/CSS/JS)启用压缩,减少传输体积。
- 图片优化:使用 WebP/AVIF 格式,或通过工具压缩 JPEG/PNG。
-
Tree Shaking & 代码分割
- 前端构建时移除未使用的代码,按需加载模块(如 Webpack 的
splitChunks)。
- 前端构建时移除未使用的代码,按需加载模块(如 Webpack 的
三、协议层升级
-
多路复用
- 单个 TCP 连接上并行传输多个请求和响应。
-
服务器推送
- 服务器主动推送关键资源(如 CSS/JS),减少客户端请求延迟。
-
0-RTT 握手(HTTP/3)
- QUIC 协议支持快速恢复会话,减少 TLS 握手时间。
四、其他
-
CDN 加速
- 将静态资源分发到全球边缘节点,缩短用户与资源的物理距离。
-
预加载与预连接
<link rel="preload">:提前加载关键资源。<link rel="preconnect">:提前建立 DNS 查询、TCP 握手等连接步骤。
cookie和token的运用机制 ⭐️⭐️ (重点)
- 1、Cookie + Session:传统方案,依赖服务器存储,适合单体应用。
- 2、Token(如 JWT):无状态方案,适合分布式或前后端分离系统。
- 无论哪种方式,本质都是通过 客户端携带标识 + 服务器验证标识 来实现状态保持。
HTTP 协议本身是无状态的,这意味着每次请求和响应之间是独立的,服务器默认不会记录之前的请求信息。但通过以下技术手段,可以实现用户登录状态的保持:
1. Cookie(客户端存储)
- 核心机制:服务器通过响应头
Set-Cookie向客户端(浏览器)下发一个唯一标识(如Session ID),浏览器后续请求会自动携带该 Cookie。 - 流程:
- 用户登录时,服务器验证账号密码后生成一个唯一
Session ID,通过Set-Cookie返回给浏览器。 - 浏览器后续每次请求都会自动在请求头
Cookie中携带此Session ID。 - 服务器通过
Session ID识别用户身份。
- 用户登录时,服务器验证账号密码后生成一个唯一
- 安全性:Cookie 需设置
HttpOnly(防XSS)、Secure(仅 HTTPS 传输)、SameSite(防CSRF)等属性。
2. Session(服务器存储)
- 核心机制:
Session ID对应服务器端的用户数据(如用户ID、权限等)。 - 流程:
- 用户登录后,服务器在内存或数据库中创建 Session 数据,关联一个
Session ID。 - 服务器将
Session ID通过 Cookie 返回给客户端。 - 后续请求中,服务器通过
Session ID查找对应的 Session 数据,验证用户身份。
- 用户登录后,服务器在内存或数据库中创建 Session 数据,关联一个
- 缺点:服务器需存储 Session 数据,高并发或分布式场景下需额外处理(如 Redis 集中存储)。
3. Token(无状态令牌)
- 核心机制:用户信息加密后直接存储在客户端(如 JWT)。
- 流程:
- 用户登录后,服务器生成一个加密的 Token(如 JWT),包含用户ID、过期时间等信息。
- Token 通过响应体返回给客户端 (可存储在 LocalStorage 或 Cookie)。
- 客户端后续请求在
Authorization请求头中携带 Token。 - 服务器解密 Token 直接验证用户身份,无需存储会话数据。
- 优点:
天然支持分布式系统,服务器无需维护 Session 状态。 - 缺点:Token 一旦泄露可能被滥用,需设置短期有效期。
安全问题
- Cookie 劫持:通过 HTTPS 加密传输、设置
Secure属性防御。 - XSS 攻击:设置
HttpOnly防止 JavaScript 窃取 Cookie。 - CSRF 攻击:使用
SameSite Cookie、CSRF Token 防御。 - Token 泄露:JWT 需设置合理有效期,敏感操作需二次验证。
cookie放哪里,cookie能做的事情和存在的价值
cookie是存在浏览器上的一小段数据,来解决 HTTP无状态机制问题,比如记录某页面关闭或者刷新后仍需要记录的信息。
属性
- cookie可以使用js在浏览器直接设置,也可以在服务器端使用HTTP协议规定的set-cookie来设置。
- 一般cookie的容量为4k左右。
- document.cookie查看当前浏览网站的cookie
运用
- 会话状态管理(如用户登录状态、购物车、游戏分数、其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题色等)
- 精准广告(平常浏览网页时有时会推出商品刚好是你最近浏览过,买过的类似东西,这些是通过cookie记录的。)
Cookie 的重点考察点
1. Cookie 属性字段
| 字段 | 说明 |
|---|---|
name=value | 键值对数据 |
domain | 指定允许访问的域(如 .example.com) |
path | 限制 Cookie 生效路径 |
expires / max-age | 控制过期时间 |
secure | 仅 HTTPS 才发送 |
HttpOnly | JavaScript 无法读取,提高安全性 |
SameSite | 防止跨站请求伪造(CSRF)攻击 |
2. Cookie 设置方式
- 后端设置(
Set-Cookie响应头) - 前端设置(
document.cookie = "key=value",受限制)
3. Cookie 的跨域规则
- 默认只发送到设置域及其子域
- 跨域访问需使用
Access-Control-Allow-Credentials: true且withCredentials = true
三、Session 的重点考察点
1. Session 原理
- 每个客户端分配一个唯一的
sessionId - 客户端通过 Cookie(默认名如
JSESSIONID)将 ID 发送给服务端 - 服务端用
sessionId找到对应的状态数据(如用户信息)
2. 存储方式
| 方式 | 说明 |
|---|---|
| 内存 | 快速,但不适合分布式(重启丢失) |
| 文件系统 | 简单可靠,性能一般 |
| 数据库/Redis | 支持持久化和分布式,性能好 |
3. 安全风险
-
Session Fixation:攻击者预设 sessionId 引导用户登录
-
Session 劫持:中间人截获 sessionId
-
解决方式:
- 登录成功后重置 sessionId
- 配合 HTTPS、防止 sessionId 泄露
四、Session 与 Cookie 配合使用
- Session 通常依赖 Cookie 来传递
sessionId - Cookie 负责持久化保存 ID,Session 负责保存服务端用户状态
- 无 Cookie 时(如某些小程序、无状态 API),可用 token(如 JWT)替代
五、延伸考点:Token 与 Session 对比
| 对比点 | Session | Token(如 JWT) |
|---|---|---|
| 存储位置 | 服务端 | 客户端(通常存在 Cookie 或 LocalStorage) |
| 状态管理 | 有状态 | 无状态 |
| 分布式支持 | 一般不友好 | 天然支持 |
| 安全性 | 不易伪造,但易劫持 | 签名机制防篡改,失效控制难 |
| 实现复杂度 | 简单 | 略复杂(涉及签名/验证) |
六、常见面试问题示例
| 问题 | 涉及考点 |
|---|---|
| Cookie 与 Session 的区别? | 存储位置、状态管理、安全性 |
| Cookie 有哪些关键属性?如何防止被窃取? | HttpOnly、Secure、SameSite |
| Session 是如何实现的?和 Cookie 有什么关系? | sessionId、状态记录 |
| Cookie 为什么有大小限制? | Cookie 会随每一次 HTTP 请求(包括静态资源请求)自动携带,若 Cookie 体积过大,会显著增加请求头大小,拖慢传输速度、占用带宽,尤其对高并发场景影响明显。 |
| 前端如何设置 Cookie? | document.cookie 注意 path 和 domain |
| Session 是如何在分布式架构中管理的? | 使用 Redis、数据库共享 |
| 如何防止 Session Fixation? | 登录后更换 sessionId |
| 使用 token 和 session 管理登录有什么差别? | 状态 vs 无状态,扩展性 vs 安全控制 |
cookie和token都存放在header里面,为什么只劫持前者
- Cookie 更易被劫持:主要因其自动携带特性和历史遗留的配置疏漏(如未设置
HttpOnly/Secure/SameSite)。- Token 相对安全:因手动管理、无自动携带逻辑,但需开发者主动实现安全措施(如 HTTPS、短期 Token)。
- 核心原则:无论是 Cookie 还是 Token,安全性取决于配置和实现,而非技术本身。
在 HTTP 协议中,Cookie 和 Token 虽然都通过 Header 传递,但劫持难度和常见攻击方式不同。以下是关键原因:
1. 自动携带机制不同
- Cookie:
- 浏览器会自动在所有符合路径和域规则的请求中携带 Cookie(即使存在跨站风险),例如:
GET /profile HTTP/1.1 Cookie: session_id=abc123 - 攻击面广:攻击者可通过 XSS、中间人劫持、CSRF 等方式窃取或滥用 Cookie。
- 浏览器会自动在所有符合路径和域规则的请求中携带 Cookie(即使存在跨站风险),例如:
- Token:
- 通常由开发者手动添加到请求头(如
Authorization: Bearer <token>),不会自动携带。 - 攻击面窄:需明确劫持 Token 并构造请求,且默认不参与跨站请求。
- 通常由开发者手动添加到请求头(如
2. 安全防护机制差异
- Cookie 的防护依赖配置:
- 若未设置
HttpOnly,可通过 XSS 直接读取 Cookie。 - 若未设置
Secure,Cookie 会通过 HTTP 明文传输。 - 若未设置
SameSite,可能被 CSRF 攻击利用(现代浏览器默认SameSite=Lax)。
- 若未设置
- Token 的防护更主动:
- Token 通常配合 HTTPS 加密传输,且无自动携带逻辑。
- 若使用短期 Token(如 JWT 设置短有效期),即使泄露危害也有限。
- JWT 可以安全地在各方之间传输信息。由于 JWT 可以被签名,接收方可以验证 JWT 的完整性和真实性,确保信息在传输过程中没有被篡改。例如,在不同服务之间传递用户信息时可以使用 JWT。
cookie和session有哪些方面的区别 ⭐️
| 对比维度 | Cookie | Session |
|---|---|---|
| 存储位置 | 客户端(浏览器) | 服务端(内存、数据库等) |
| 本质 | 一段 键值对文本信息 | 一个 服务端维护的状态标识 |
| 生命周期 | 默认会话级,支持设置过期时间 | 一般是浏览器关闭或超时后销毁 |
| 大小限制 | 单个域名下最多 4KB | 理论不限,但受服务端资源限制 |
| 安全性 | 容易被劫持、伪造,依赖 HTTPS 保护 | 相对安全,但需防止 Session Fixation |
| 使用场景 | 状态保持、轻量存储、前后端身份标识 | 登录认证、权限控制、用户状态管理 |
性能影响
- Cookie:每次客户端向服务器发送请求时,
都会在请求头中携带该域名下的所有 Cookie 信息,这会增加请求的大小,尤其是在 Cookie 数量较多或数据较大的情况下,会对网络性能产生一定的影响。 - Session:客户端只需要在请求头中携带会话 ID,而会话数据存储在服务器端,因此请求的大小相对较小,对网络性能的影响也较小。但是,服务器需要管理和维护大量的会话数据,会占用一定的服务器资源。
有效期
- Cookie:可以设置不同的有效期。会话级 Cookie 在浏览器关闭时自动失效;持久化 Cookie 可以设置具体的过期时间,在过期时间之前,即使浏览器关闭,Cookie 仍然有效。
- Session:通常有一个固定的有效期,当会话过期后,服务器会自动销毁该会话及其相关的数据。会话的有效期可以根据应用的需求进行设置。
使用 cookie 时需要考虑的问题
-
Cookie:默认情况下,Cookie 是基于域名的,不同域名之间的 Cookie 是相互隔离的。如果需要实现跨域共享 Cookie,需要进行一些额外的配置,如设置
domain属性。 -
因为存储在客户端,容易被客户端篡改,使用前需要验证合法性,不要存储敏感数据(比如用户密码、账户余额)
-
尽量减少 cookie 的体积,能存储的数据量不能超过 4kb
-
一个浏览器针对一个网站最多存 20 个 Cookie,浏览器一般只允许存放 300 个 Cookie
-
设置正确的 domain 和 path,减少数据传输
-
cookie 无法跨域
-
移动端对 cookie 的支持不是很好,所以移动端常用的是 token
使用 session 时需要考虑的问题
-
将 session 存储在服务器里面,当用户同时在线量比较多时,这些 session 会占据较多的内存,需要在服务端定期的去清理过期的 session
-
当网站采用集群部署的时候,会遇到多台 web 服务器之间如何做 session 共享的问题。因为 session 是由单个服务器创建的,但是处理用户请求的服务器不一定是那个创建 session 的服务器,那么该服务器就无法拿到之前已经放入到 session 中的登录凭证之类的信息了。
-
当多个应用要共享 session 时,除了以上问题,还会遇到跨域问题,因为不同的应用可能部署的主机不一样,需要在各个应用做好 cookie 跨域的处理。
-
sessionId 是存储在 cookie 中的,假如浏览器禁止 cookie 或不支持 cookie 怎么办?一般会把 sessionId 跟在 url 参数后面即重写 url,
所以 session 不一定非得需要靠 cookie 实现
使用 token 时需要考虑的问题
- 如果你认为用数据库来存储 token 会导致查询时间太长,
可以选择放在内存当中。比如 redis 很适合你对 token 查询的需求。 - token 完全由应用管理,所以它可以避开同源策略
token 可以避免 CSRF 攻击 (因为不需要 cookie 了)- 移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token
cookie的存放位置,删除机制
存放位置
Cookie 是由服务器发给客户端的特殊信息,以文本文件方式存储在客户端,具体位置因操作系统和浏览器而异:
从存储介质角度,Cookie 有以下存储形式:
- 文本文件:早期浏览器常将 Cookie 以文本文件存于硬盘特定文件夹,不同浏览器路径和命名规则有别。
- 数据库:部分现代浏览器(如用 SQLite、IndexedDB 等)将 Cookie 存于数据库,更安全且便于管理查询。
- 内存:有些浏览器在内存存储 Cookie,仅在浏览器会话期间有效,关闭浏览器即清除,用于临时存会话或其他临时数据。
删除机制
-
自动删除
- 会话级 Cookie:一旦浏览器关闭,这类 Cookie 就会自动清除 。
- 过期删除:若 Cookie 设置了具体的过期时间 (Expires 属性 ) ,当到达该时间点,浏览器会自动将其删除。比如网站设置记住登录状态的 Cookie 有效期为一个月,一个月后该 Cookie 自动失效删除。在 Web 开发中,可通过设置 Cookie 的过期时间为 0 来实现删除。以 JavaScript 为例,
document.cookie = "cookieName=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";,这里将指定名称(cookieName)的 Cookie 过期时间设为过去时间,浏览器就会删除它 。在服务器端,如 PHP 中使用setcookie('cookieName', '', time() - 3600);(将过期时间设为一小时前)来删除 Cookie 。
-
手动删除
- 浏览器设置:几乎所有浏览器都提供手动删除 Cookie 的功能。
如何设置http缓存 ⭐️⭐️⭐️ 重点,热点
以下是设置 HTTP 缓存的详细步骤和策略,涵盖 强缓存 和 协商缓存 的配置方法,适用于浏览器和 CDN 场景:
一、HTTP 缓存类型及核心头字段
| 缓存类型 | 头字段 | 作用 |
|---|---|---|
| 强缓存 | Cache-Control | 控制资源缓存的行为和有效期(优先级最高) |
Expires | 指定资源过期时间(HTTP/1.0,优先级低) | |
| 协商缓存 | ETag / If-None-Match | 资源内容哈希值验证 |
Last-Modified / If-Modified-Since | 资源修改时间验证 |
二、强缓存配置(直接从本地缓存读取)
1. 设置 Cache-Control(推荐)
- 语法示例:
Cache-Control: max-age=31536000, public, immutable - 常用指令:
max-age=<seconds>:资源缓存时间(如31536000表示 1 年)。public:允许所有缓存(浏览器、CDN、代理)缓存资源。private:仅允许浏览器缓存(禁止 CDN 和代理缓存)。no-cache:强制协商缓存(需向服务器验证)。no-store:禁止任何缓存(敏感数据场景)。immutable:声明资源永不变化(浏览器跳过验证)。
2. 设置 Expires(兼容旧浏览器)
- 语法示例:
Expires: Wed, 21 Oct 2025 07:28:00 GMT - 注意:若同时设置
Cache-Control和Expires,以Cache-Control为准。
3. 适用场景
- 静态资源(JS/CSS/图片):设置长期强缓存(如 1 年),通过文件名哈希(如
app.a1b2c3.js)实现内容更新。
三、协商缓存配置(向服务器验证缓存有效性)
1. 设置 ETag(基于内容哈希)
- 服务端返回:
ETag: "a1b2c3d4e5" - 客户端请求:
If-None-Match: "a1b2c3d4e5" - 验证流程:
服务端比较客户端传来的If-None-Match与当前资源ETag:- 匹配 → 返回
304 Not Modified(空响应体)。 - 不匹配 → 返回
200 OK和新资源。
- 匹配 → 返回
2. 设置 Last-Modified(基于修改时间)
- 服务端返回:
Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT - 客户端请求:
If-Modified-Since: Wed, 21 Oct 2023 07:28:00 GMT - 验证流程:
服务端比较客户端传来的If-Modified-Since与资源修改时间:- 未修改 → 返回
304 Not Modified。 - 已修改 → 返回
200 OK和新资源。
- 未修改 → 返回
3. 适用场景
- 动态资源(HTML、API 响应):设置短时间缓存(如
max-age=0),依赖协商缓存验证更新。
四、缓存策略组合示例
1. 静态资源(强缓存 + 文件名 hash)
Cache-Control: public, max-age=31536000, immutable
- 文件名带哈希:如
style.a1b2c3.css,内容变化时 URL 改变,自动跳过缓存。 - 服务器配置示例(Nginx):
location /static/ { add_header Cache-Control "public, max-age=31536000, immutable"; }
2. 动态内容(协商缓存)
Cache-Control: no-cache
Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT
ETag: "a1b2c3d4e5"
- 服务器配置示例(Express.js):
app.get('/api/data', (req, res) => { const data = getData(); res.set({ 'Cache-Control': 'no-cache', 'Last-Modified': new Date().toUTCString(), 'ETag': generateETag(data) }); res.send(data); });
3. 禁止缓存(敏感数据)
- 设置响应头:
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Expires: 0
五、调试与验证
-
浏览器开发者工具:
- Network 面板:查看请求的
Status Code(200/304)和响应头。 - 响应状态码:
200 (from disk cache)或200 (from memory cache)。disk cache表示强缓存,(from memory cache)表示内存缓存。
- Network 面板:查看请求的
-
命令行工具:
curl -I http://example.com/resource.js # 查看返回的 Cache-Control、ETag 等头字段
disk cache(磁盘缓存)和 from memory cache(内存缓存)都是浏览器缓存静态资源(如图片、JS、CSS)的方式,核心区别是缓存位置不同,导致读取速度、持久性和适用场景完全不一样。
核心区别对比
| 对比维度 | from memory cache(内存缓存) | disk cache(磁盘缓存) |
|---|---|---|
| 存储位置 | 浏览器内存 | 电脑硬盘 / SSD |
| 读取速度 | 极快(微秒级) | 较慢(毫秒级) |
| 持久性 | 临时,关闭标签 / 浏览器后消失 | 持久,重启后仍存在 |
| 资源体积偏好 | 体积小的资源 | 体积较大的资源 |
简单总结:内存缓存是 “临时快取”,为当前会话提速;磁盘缓存是 “长期仓库”,为下次访问省钱省时间。浏览器会自动根据资源特性,优先用内存缓存,再用磁盘缓存,最后才从服务器下载。
缓存优先级
浏览器优先读取顺序:
Service Worker 缓存 > Memory Cache > Disk Cache > Web Storage 缓存 > 请求服务器
六、常见问题与解决方案
| 问题 | 解决方案 |
|---|---|
| 资源更新后用户看到旧版本 | 修改文件名(添加哈希)或增加查询参数(如 ?v=2) |
| 缓存时间过长导致无法及时更新 | 动态资源设置 max-age=0 或 no-cache,依赖协商缓存 |
| CDN 不遵循缓存头 | 检查 CDN 配置,确保不覆盖 Cache-Control,或设置 CDN 缓存规则与服务器一致 |
| 缓存敏感数据(如用户信息) | 设置 Cache-Control: private, no-store |
七、面试常见问题示例
| 面试问题 | 涉及考点 |
|---|---|
| 浏览器强缓存和协商缓存的区别? | 状态码、是否请求服务器 |
| Cache-Control 常见取值有哪些? | no-cache, no-store, max-age |
| ETag 与 Last-Modified 有什么区别? | 精度、性能、误判可能性 |
| HTML 页面应该如何设置缓存策略? | 通常设置为 no-cache |
| 浏览器缓存有哪些层级? | memory、disk、Service Worker |
| 如何设计静态资源缓存方案? | 文件名加 hash,配置强缓存头 |
常见考点
- 缓存的基本概念
- 强缓存 vs. 协商缓存
- 强缓存:
Cache-Control、Expires - 协商缓存:
ETag、Last-Modified - 缓存优先级:强缓存 > 协商缓存 > 无缓存
- 缓存的生命周期
- 缓存控制指令:
max-age、s-maxage、no-cache、no-store、must-revalidate - Cache-Control的常见值及作用
- 浏览器缓存的类型:内存缓存、磁盘缓存
- HTTP请求中的缓存相关头部:
If-None-Match、If-Modified-Since - Service Worker缓存
- 缓存的影响因素:请求头、响应头、用户设置等
- 跨域资源缓存问题:CORS和缓存
- 缓存清除机制
- 缓存穿透与缓存雪崩问题
- CDN与缓存
- 版本控制和缓存更新策略
HTML 通常不使用强缓存
- 避免首页更新被缓存 → 设置为
no-cache或短时间缓存
<meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate">
总结
- 强缓存:适合内容不变的静态资源,通过
Cache-Control: max-age+ 文件名哈希实现长期缓存。 - 协商缓存:适合动态内容,通过
ETag或Last-Modified验证资源是否更新。 - 组合策略:静态资源强缓存 + 动态内容协商缓存,结合 CDN 加速。
- 调试工具:浏览器开发者工具和命令行工具验证缓存行为。
浏览器的存储机制
浏览器的存储机制涵盖多种技术,目的是满足 Web 应用在不同场景下的数据持久化、缓存和离线访问需求。它们各自具有不同的存储容量、生命周期、安全策略和访问方式,理解这些机制对于构建高效、安全的前端应用至关重要。
一、浏览器存储机制分类
1. Cookie
最早期的存储机制,主要用于会话管理和身份认证。
- 容量限制:单个约 4KB,总数有限制;
- 生命周期:可设置过期时间或为会话级;
- 访问方式:由浏览器自动在 HTTP 请求头中携带,也能通过 JS 访问(除非设置 HttpOnly);
- 安全性:可设置 HttpOnly、Secure、SameSite 防范安全风险。
2. Web Storage(LocalStorage 和 SessionStorage)
HTML5 新增的简单键值对存储方案。
- LocalStorage:永久存储,关闭浏览器数据仍保留,同源可访问;
- SessionStorage:页面会话存储,关闭标签页即清空;
- 容量:一般为 5~10MB;
- 访问方式:同步 API,容易使用但可能阻塞主线程。
3. IndexedDB
浏览器内置的底层结构化数据库,支持事务和索引,适合复杂和大容量数据存储。
- 容量:远大于 LocalStorage,通常以设备剩余空间为限;
- 访问方式:异步 API,支持复杂操作;
- 用途:离线应用、大数据缓存、文件存储等。
4. Cache Storage
由 Service Worker 管理的请求和响应缓存,用于离线和加速访问。
- 容量:较大,依赖设备和浏览器策略;
- 访问方式:异步 Promise API;
- 用途:缓存静态资源、接口响应,实现离线支持。
5. Service Worker
虽然不是存储机制本身,但作为浏览器后台代理进程,管理 Cache Storage,实现网络请求拦截和缓存策略,是现代离线应用的核心。
- 生命周期独立于页面,可在后台运行;
- 控制页面的网络请求,提供离线能力和资源预缓存;
- 可结合 Cache Storage 和 IndexedDB 进行数据管理。
二、存储机制的生命周期与访问作用域
- Cookie:基于域和路径,可设置 HttpOnly、Secure 限制访问;
- LocalStorage/SessionStorage:基于同源策略,SessionStorage 进一步限定于标签页会话;
- IndexedDB 和 Cache Storage:基于同源,支持版本控制和升级;
- Service Worker:独立于页面,能控制同源下的所有相关页面。
三、容量限制与性能影响
- Cookie 容量最小,且会随每次请求自动发送,影响网络性能;
- LocalStorage/SessionStorage 适合轻量存储,容量适中;
- IndexedDB 和 Cache Storage 容量大,适合海量数据和文件缓存;
- Service Worker 通过异步调度,避免阻塞主线程。
四、安全与隐私考虑
- Cookie 可被服务器访问,设置 HttpOnly 避免脚本窃取;
- Web Storage、IndexedDB 只能由同源脚本访问,防止跨站数据泄漏;
- Service Worker 需 HTTPS 环境,避免被恶意注入;
- 用户隐私模式下,存储行为可能受限,数据不保证持久。
五、应用场景及选择建议
- 需要与服务器频繁交互、会话维持时用 Cookie;
- 存储简单配置、少量数据用 LocalStorage;
- 页面会话临时数据用 SessionStorage;
- 大规模结构化数据和离线存储用 IndexedDB;
- 静态资源及请求缓存用 Cache Storage,配合 Service Worker 提升离线体验和性能;
- Service Worker 负责管理缓存和拦截网络请求,实现 PWA 功能。
常见考点
面试考察点通常围绕存储类型、特点、使用场景、容量限制、安全性和生命周期展开:
- 浏览器有哪些本地存储方式?分别有什么特点?
- Cookie 和 LocalStorage 的区别是什么?
- 如何安全使用 Cookie?
HttpOnly和Secure有什么作用? - SessionStorage 和 LocalStorage 有哪些区别?
- IndexedDB 的优势和适用场景?
- 如何使用 Cache Storage 实现离线缓存?
- 存储容量限制和浏览器兼容性问题?
- 如何避免本地存储的数据被篡改或泄露?
- 存储的生命周期和访问范围如何理解?
- 同源策略对浏览器存储的影响?
关联面试题
存储容量限制 & 浏览器兼容性
| 存储类型 | 容量限制 | 兼容性 |
|---|---|---|
| Cookie | 4KB / 个,最多 20 个 / 域名 | 所有浏览器兼容 |
| localStorage/sessionStorage | 5MB / 域名 | IE8+、主流浏览器均支持 |
| IndexedDB | 一般 250MB~ 无上限(视浏览器 / 设备) | IE10+、主流浏览器支持 |
| Service Worker Cache | 同 IndexedDB | Chrome/Firefox/Edge 支持,Safari 11.1+ 支持 |
总结:Cookie 容量最小,localStorage 够用且兼容性好,大容量数据用 IndexedDB。
避免本地存储数据篡改 / 泄露
- 敏感数据不存前端:密码、token 等核心数据绝不直接存,可存加密后的摘要(如 AES 加密)。
- 数据签名校验:存数据时附带后端生成的签名(如 HMAC),读取时校验签名,篡改则失效。
- 合理设置存储属性:Cookie 加
HttpOnly(防 JS 读取)、Secure(仅 HTTPS 传输)、SameSite=Strict(防 CSRF)。 - 定期清理 + 加密存储:敏感数据用完即删,
localStorage存数据时用加密算法(如 CryptoJS)处理。
存储生命周期 & 访问范围
| 存储类型 | 生命周期 | 访问范围 |
|---|---|---|
| Cookie | 可设置 expires/max-age(持久),或会话级(关闭浏览器失效) | 同源 + 指定域名 / 路径,请求自动携带 |
| localStorage | 持久化,除非手动删除 / 清理缓存 | 同源域名内所有页面共享 |
| sessionStorage | 会话级,关闭标签页 / 浏览器即失效 | 仅当前标签页有效,同源其他标签页不可访问 |
| IndexedDB | 持久化,手动删除才消失 | 同源域名内共享 |
同源策略对浏览器存储的影响
同源策略(协议 + 域名 + 端口一致)是浏览器安全核心,限制不同源页面访问彼此存储数据:
- 同源页面:可共享
localStorage/sessionStorage/Cookie/IndexedDB。 - 不同源页面:完全隔离,无法读取对方存储的数据。
- 特例:Cookie 可通过设置
domain实现主域下子域名共享(如a.example.com和b.example.com共享)。
cookie 的有效时间设置为 0 会怎么样
Cookie过期时间设置为0,表示跟随系统默认,其销毁与Session销毁时间相同,会在浏览器关闭后删除。
使用cookie、session维持登录状态的原理是什么?
什么是 Samesite Cookie 属性?
SameSite 是HTTP响应头 Set-Cookie 的属性之一。它允许声明该 Cookie 是否仅限于第一方或者同一站点上下文。
- 将 Samesite 设为
strict,这种称为严格模式,表示这个 cookie 在任何情况下都不可能作为第三方 cookie。 - 将 Samesite 设为
Lax,这种模式称为宽松模式,也是目前浏览器中的默认值。如果这个请求是个 GET 请求,并且这个请求改变了当前页面或者打开了新的页面,那么这个 cookie 可以作为第三方 cookie,其余情况下都不能作为第三方 cookie。使用这种方法的缺点是,因为它不支持子域,所以子域没有办法与主域共享登录信息,每次转入子域的网站,都需要重新登录。还有一个问题就是它的兼容性不够好。 - 将 Samesite 设为
None,Cookie将在所有上下文中发送,即允许跨域发送。
响应头设置方式:
Set-Cookie: flavor=choco; SameSite=None; Secure
Service Worker 是如何缓存 http 请求资源的?
Service Worker 通过拦截 HTTP 请求,并使用缓存 API 存储和管理缓存资源,使得应用能够离线访问,提高了应用的性能和可靠性。核心过程包括注册 Service Worker、在 install 事件中预缓存资源、在 fetch 事件中拦截请求并从缓存或网络返回资源,以及在 activate 事件中进行缓存清理。
Cookie 的 SameSite 属性有什么作用? 防止 CSRF 攻击和用户追踪
WebWorker、SharedWorker 和 ServiceWorker 有哪些区别?
Service worker是什么?
service worker是PWA的重要组成部分,W3C 组织早在 2014 年 5 月就提出过 Service Worker 这样的一个 HTML5 API ,主要用来做持久的离线缓存,也是Web Worker的升级版。
Service worker (简称 SW) 是一个注册在指定源和路径下的事件驱动 Worker。它采用 JavaScript 控制关联的页面或者网站,拦截并修改访问和资源请求,细粒度地缓存资源。你可以完全控制应用在特定情形(最常见的情形是网络不可用)下的表现。
CDN的作用和原理 ⭐️ 重点
CDN 通过 边缘节点缓存 + 智能路由分发 实现了内容的高效传递,成为现代 Web 服务的核心基础设施。
安装推送的类型
1)主动推送:由源站服务器,负责分发内容至CDN边缘节点,然后智能DNS引导用户去就近CDN节点。
2)被动推送:用户通过智能DNS,访问到就近CDN节点,然后索引文件,本地没发现该文件,然后本地就从源站请求数据,然后缓存到本地,再推送给用户。
CDN(内容分发网络) 是一种通过 分布式边缘节点缓存内容 的技术,旨在加速用户访问速度、降低源站负载并提升服务稳定性。以下是其核心作用与工作原理的详细解析:
一、CDN 的核心作用
1、提高用户访问的速度。
2、减轻源站服务器的压力。
3、提高并发能力(分布式架构)。
内容分发网络(CDN)是一种通过分布式服务器节点内容传输的技术,旨在提升用户访问网站或应用的速度与稳定性。以下是对CDN的详细解析:
1. CDN的核心原理
- 地理分布:CDN在全球多个位置部署边缘节点,缓存源站的静态资源(如图片、视频、CSS/JS文件)。
- 就近访问:用户请求被路由到最近的节点,减少物理距离带来的延迟。
- 缓存机制:节点存储内容,减少直接回源站的请求,降低源站负载。
2. CDN的关键组成部分
- 边缘节点(Edge Server):直接与用户交互的服务器,负责内容缓存和快速响应。
- 中心节点(Origin Shield):部分CDN设置中心层,进一步减少源站压力。
- 负载均衡系统:通过DNS或Anycast技术分配用户请求到最优节点。
- 回源机制:边缘节点未缓存或缓存过期时,向源站请求资源并存储。
3. CDN的工作流程
- 用户发起请求:输入网址。
- DNS解析:CDN的智能DNS根据用户位置返回最佳节点IP。
- 节点响应:
- 若资源已缓存且未过期,直接返回给用户。
- 若资源过期或未缓存,节点从源站拉取并更新缓存。
4. CDN的主要应用场景
- 静态资源加速:网页、图片、文档等内容的全球分发。
- 大文件下载:游戏更新、软件安装包的分发。
5. CDN的优势
- 提升速度:用户请求被路由到最近的节点,减少物理距离带来的延迟,改善用户体验(如页面加载时间缩短30%-50%)。
- 减轻源站服务器的压力:源站流量减少。
- 提高并发能力(分布式架构)
- 提升可用性和抗 DDoS 攻击能力
6. 挑战与注意事项
- 动态内容限制:传统CDN对动态内容(如实时数据)加速效果有限,需结合其他技术。
- 成本管理:按流量或请求计费可能增加费用,需根据业务需求选择套餐。
- 隐私合规:全球节点可能涉及数据跨境存储,需符合GDPR等法规。
7. 主流CDN服务商
- 企业级:Akamai(全球最大)、Cloudflare(以安全著称)、AWS CloudFront(深度集成云服务)。
- 国内服务:阿里云CDN、腾讯云CDN、网宿科技。
- 开源方案:Traefik、Caddy(轻量级反向代理/CDN功能)。
8. 实际案例
- 电商大促:天猫“双11”通过CDN处理PB级流量,避免服务器崩溃。
- 视频平台:抖音使用CDN实现低延迟直播,支持千万级并发。
- 全球化企业:Spotify利用CDN快速分发音乐文件至不同地区用户。
9. 负载均衡系统
由于没有返回 IP 地址,于是本地 DNS 会向负载均衡系统再发送请求 ,则进入到 CDN 的全局负载均衡系统进行智能调度:
-
看用户的 IP 地址,查表得知地理位置,找相对最近的边缘节点
-
看用户所在的运营商网络,找相同网络的边缘节点
-
检查边缘节点的负载情况,找负载较轻的节点
-
其他,比如节点的 “健康状况”、服务能力、带宽、响应时间等
结合上面的因素,得到最合适的边缘节点,然后把这个节点返回给用户,用户就能够就近访问 CDN 的缓存代理
CDN已成为现代互联网基础设施的核心组件,尤其在数字化转型和全球化业务扩展中不可或缺。通过CDN的负载均衡系统,智能调度边缘节点提供服务,不仅能提升用户体验,还能增强业务的稳定性和安全性。
CDN 节点缓存是如何更新的
CDN 节点缓存更新核心是触发缓存失效,主要有 3 类机制:
-
过期自动更新依据资源响应头的缓存策略(如
Cache-Control的max-age),缓存到期后,CDN 节点会主动回源站拉取最新资源,更新本地缓存。 -
主动刷新(主动 Purge)
- 开发者通过 CDN 控制台或 API,提交需要刷新的资源 URL / 目录,强制 CDN 节点删除对应缓存。
- 适用场景:发布紧急版本、修复线上 bug 时,立即让用户获取最新资源。
- 注意:频繁全量刷新会增加源站压力,建议精准刷新(指定 URL)。
-
被动刷新(缓存穿透触发) 当用户请求的资源在 CDN 节点已过期 / 不存在时,节点会回源拉取最新资源并缓存,同时返回给用户。
如何避免缓存过期 & 强制刷新方法
-
避免过期:资源加内容哈希命名(如
app.5f8a.js),配合max-age=31536000(缓存 1 年),内容变则 URL 变 -
强制刷新
- 客户端:
Ctrl+F5或 清缓存 - 开发 / 测试:URL 加版本号(
app.js?v=2) - 生产环境:CDN 主动刷新 或 设
Cache-Control: no-cache(强制协商缓存)
- 客户端:
如何区分“热资源”和“冷资源”的缓存策略?
热资源:访问频率高、时效性强、带宽消耗大(如首页 JS/CSS、热门图片、活动页)冷资源:访问频率低、更新少、存储占比高(如历史文档、归档图片、低频接口数据)
| 维度 | 热资源缓存策略 | 冷资源缓存策略 |
|---|---|---|
| 缓存有效期 | 适中(如 1~24 小时),避免过期后大量回源 | 长期(如 30 天~1 年),降低回源次数 |
| CDN 节点部署 | 优先部署在边缘节点(靠近用户),提升命中率 | 部署在中心节点,节省边缘节点存储空间 |
| 刷新策略 | 支持主动刷新,保证时效性 | 仅被动刷新(过期后回源),减少运维成本 |
| 缓存粒度 | 细粒度(按文件 / URL 缓存),精准控制更新 | 粗粒度(按目录缓存),降低管理复杂度 |
| 优先级 | 高优先级缓存,分配更多带宽 / 内存 | 低优先级缓存,可被热资源挤出(LRU 淘汰机制) |
| 典型配置 | Cache-Control: public, max-age=3600 + ETag | Cache-Control: public, max-age=2592000 + 不设置协商缓存 |
Vue2 项目实践:
- 热资源(
app.xxx.js、vendor.xxx.js):webpack 构建时加哈希,CDN 边缘节点缓存,设置 1 天有效期。 - 冷资源(
static/archives/xxx.pdf):上传至 CDN 低频存储节点,设置 30 天有效期,不配置主动刷新。
CDN面试常见问题
-
CDN 的原理是什么?它解决了哪些问题?
-
浏览器请求 CDN 资源时如何定位到最近的节点?
-
CDN 缓存失效策略有哪些?如何手动刷新?
-
如何让资源文件在更新后立即生效?文件哈希、CND主动刷新、禁用缓存
-
使用 CDN 的时候,如何配置静态资源的缓存策略?
推荐组合:
Cache-Control: public, max-age=86400+ETagpublic:允许 CDN / 代理缓存max-age=86400:缓存 1 天ETag:资源更新时触发协商缓存,返回 304 减少带宽
-
CDN 是否可以缓存动态接口?如果要缓存,有哪些方式?
CDN 可以缓存动态接口,核心是 标准化动态内容的缓存条件,适用场景:非实时数据(如商品列表、文章详情)。
-
CDN 如何支持 HTTPS? CDN 支持 HTTPS 核心是证书部署 + 协议转换,步骤如下:
- 配置 SSL 证书:在 CDN 控制台上传自有证书,或直接使用厂商提供的免费证书(自动续签)。
- 边缘节点握手:用户与 CDN 边缘节点建立 HTTPS 连接,完成加密传输。
- 回源协议可选:CDN 与源站之间可选择 HTTPS(安全)或 HTTP(内网环境高效)通信。
- 可选强制跳转:配置 HTTP 请求 301 重定向到 HTTPS,避免混合内容风险。
-
CDN 缓存命中率下降的可能原因有哪些?
-
资源粒度问题:资源 URL 碎片化(如带随机参数),导致缓存键过多,无法复用
-
缓存时间过短:
max-age设置太小,缓存频繁过期,大量请求回源 -
冷门资源占比高:冷资源访问频率低,缓存易被 LRU 算法淘汰
-
缓存配置错误:源站返回
Cache-Control: private(禁止 CDN 缓存)或no-cache -
用户地域分散:部分边缘节点资源未预热,首次请求均回源
-
-
CDN 如何处理多个用户同时请求一个不存在的资源?
- 首个用户请求不存在的资源 → CDN 回源查询 → 源站返回
404 - CDN 缓存这个
404响应(默认短时效,如 1~5 分钟) - 同时间段内其他用户请求该资源 → 直接返回缓存的
404,不再回源
- 首个用户请求不存在的资源 → CDN 回源查询 → 源站返回
-
为什么推荐将静态资源放到cdn上? 推荐静态资源放 CDN 核心是 提速、降本、稳服务,简单说三点:
- 就近访问,加载更快:CDN 边缘节点分布广,用户从最近节点取资源,不用跨地域连源站,大幅降低延迟(比如图片、JS 加载时间减半)。
- 分流减压,降低成本:源站不用处理海量静态资源请求,带宽压力骤减;同时 CDN 按使用量计费,比自建高带宽服务器更划算。
- 提升稳定性,抗峰值:CDN 有负载均衡和容灾能力,秒杀、大促等高并发场景下,能避免源站宕机,保证资源正常访问。
谈谈你对TCP三次握手和四次挥手的理解
三次握手(连接建立)
-
第一次握手(SYN)
- 客户端发送带有SYN(同步序列号)标志的数据包,并选择初始序列号(ISN),进入
SYN_SENT状态。 - 目的:告知服务器客户端希望建立连接,并同步初始序列号。
- 客户端发送带有SYN(同步序列号)标志的数据包,并选择初始序列号(ISN),进入
-
第二次握手(SYN-ACK)
- 服务器收到SYN后,发送带有SYN和ACK(确认)标志的数据包,确认客户端的序列号(ISN+1),并发送自己的ISN,进入
SYN_RECEIVED状态。 - 目的:确认客户端的请求,并同步服务器的初始序列号。
- 服务器收到SYN后,发送带有SYN和ACK(确认)标志的数据包,确认客户端的序列号(ISN+1),并发送自己的ISN,进入
-
第三次握手(ACK)
- 客户端收到SYN-ACK后,发送ACK标志的数据包,确认服务器的序列号(ISN+1),双方进入
ESTABLISHED状态。 - 目的:确认服务器的响应,完成双向通信准备。
- 客户端收到SYN-ACK后,发送ACK标志的数据包,确认服务器的序列号(ISN+1),双方进入
为什么需要三次握手,两次不行吗?
确保双向通信能力:三次交互验证了双方的发送和接收能力。
- 第一次握手:客户端发送网络包,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
- 第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
- 第三次握手:客户端发包,服务端收到了。
这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
四次挥手(连接断开)
-
第一次挥手(FIN)
- 如客户端 发送FIN标志的数据包,进入
FIN_WAIT_1状态。 - 含义:不再发送数据,但可接收数据。
- 如客户端 发送FIN标志的数据包,进入
-
第二次挥手(ACK)
- 如服务器 收到FIN后,发送ACK确认,进入
CLOSE_WAIT状态。 - 如客户端 收到ACK后进入
FIN_WAIT_2状态。 - 含义:确认收到关闭请求,允许服务器处理剩余数据。
- 如服务器 收到FIN后,发送ACK确认,进入
-
第三次挥手(FIN)
- 如服务器 处理完数据后,发送FIN标志的数据包,进入
LAST_ACK状态。 - 含义:通知如客户端已准备好关闭连接。
- 如服务器 处理完数据后,发送FIN标志的数据包,进入
-
第四次挥手(ACK)
- 如客户端 收到FIN后,发送ACK确认,进入
TIME_WAIT状态(等待2MSL时间后关闭)。 - 如服务器 收到ACK后立即关闭连接。
- 含义:确保被动方收到确认,防止报文丢失导致的重传。
- 如客户端 收到FIN后,发送ACK确认,进入
为何需要四次?
因为当服务端收到客户端的 SYN 连接请求报文后,可以直接发送 SYN+ACK 报文。其中 ACK 报文是用来应答的,SYN 报文是用来同步的。但是关闭连接时,当服务端收到 FIN 报文时,很可能并不会立即关闭 SOCKET,所以只能先回复一个 ACK 报文,告诉客户端,"你发的 FIN 报文我收到了"。只有等到服务端所有的报文都发送完了,才能发送 FIN 报文,因此不能一起发送。故需要四次挥手。
总结
- 三次握手:确保双方具备收发能力,同步序列号,防止历史连接问题。
- 四次挥手:优雅关闭双向通道,处理剩余数据,保证可靠性。
- 优化实践:减少频繁连接(复用连接,如HTTP Keep-Alive)。
TCP 有哪些手段保证可靠交付 / TCP 为什么是可靠的 ⭐️ 重点
1.确认应答(ACK)机制
- 原理:发送方将数据分割成报文段发送给接收方,接收方收到报文段后,会向发送方发送一个确认(ACK)报文,其中包含确认号,该确认号表示接收方已成功接收该序号之前的所有数据。例如,接收方收到序号为 1 - 100 的字节数据,会返回确认号为 101 的 ACK 报文,告知发送方 1 - 100 字节已成功接收。
- 作用:发送方通过接收 ACK 报文,能知晓哪些数据已被成功接收,哪些可能丢失需要重传,
以此确保数据不丢失。
2.超时重传机制
- 原理:发送方每发送一个报文段,就启动一个定时器。若在定时器设置的重传时间(RTO,Retransmission Time - Out )内未收到对应的 ACK 报文,就认为该报文段可能在传输中丢失或 ACK 报文丢失,进而重传该报文段 。RTO 的设置至关重要,它会根据连接往返时间(RTT,Round Trip Time )动态调整。例如,在网络状况较好时,RTT 较短,RTO 也会相应缩短,使重传更及时;网络拥堵时,RTT 变长,RTO 也增大,避免不必要的重传加剧网络拥塞。
- 作用:在数据传输出现
丢包等异常时,通过重传确保数据最终能可靠到达接收方。
3.序列号与确认号机制
- 原理:TCP 给每个要发送的字节数据都分配一个序列号,发送方按顺序发送报文段。接收方根据序列号对收到的数据进行排序,重组出正确顺序的字节流。确认号则是接收方告知发送方下一个期望接收的字节序号。例如,发送方发送的第一个报文段包含序列号为 1 - 100 的字节,接收方若正确接收,返回的确认号为 101;若只收到序列号 1 - 50 的字节,会缓存这些数据,等待后续 51 - 100 字节到达后再一起确认,或者先返回确认号为 51 的报文,要求发送方重传 51 - 100 字节。
- 作用:保证数据按序到达接收方,
防止数据乱序或重复,确保接收方最终能按正确顺序将数据交付给应用层。
4.校验和机制
- 原理:发送方在发送报文段前,对报文段首部和数据部分的所有 16 位字(以二进制形式)相加,然后将结果取反,得到校验和,并将其放置在 TCP 首部。接收方收到报文段后,同样对报文段进行校验和计算,
再与接收到的校验和进行比较。 - 作用:检测数据在传输过程中是否因网络干扰等原因发生变化(如比特翻转)。若校验和不匹配,接收方会丢弃该报文段,不发送 ACK 确认,促使发送方超时重传,
保证接收数据的正确性。
5.流量控制机制
- 原理:利用滑动窗口协议实现。接收方在返回的 ACK 报文中,通过窗口字段告知发送方自己
接收窗口大小。发送方依据接收方通告的窗口大小,动态调整自己的发送速率,发送窗口大小不会超过接收窗口。例如,接收方通告窗口大小为 1000 字节,发送方在未收到新的窗口调整通知前,最多只能发送 1000 字节的数据。 - 作用:防止发送方发送数据过快,导致接收方缓冲区溢出而丢包,确保接收方有足够能力处理接收的数据,
保证发送和接收速度。
6.拥塞控制机制
原理:TCP 拥塞控制有慢启动、拥塞避免、快速重传、快速恢复等算法。
- 慢启动时,发送方初始拥塞窗口(cwnd,Congestion Window)较小,一般为一个最大报文段长度(MSS,Maximum Segment Size),每收到一个 ACK 确认,cwnd 增加一个 MSS,使发送速率逐渐提升;
- 达到慢启动门限(ssthresh)后进入拥塞避免阶段,此后每收到一个 ACK,cwnd 增加 1/cwnd 个 MSS,避免网络拥塞快速加剧;
- 当发送方收到三个重复的 ACK 时,进入快速重传,立刻重传丢失的报文段,而不是等待超时;
- 快速重传后进入快速恢复阶段,调整 cwnd 和 ssthresh 等参数,继续控制发送速率。
作用:根据网络的拥塞状况动态调整发送方的发送速率,避免网络出现拥塞,保证网络整体的可靠传输。
UDP 为什么更快?
- 无需建立连接(无三次握手)
- 没有确认和重传机制那些机制
TCP如何做拥塞控制
1.慢启动
2.拥塞控制
3.快重传
4.快恢复
什么是TCP粘包
TCP 粘包是指在基于 TCP 协议进行网络通信时,接收方收到的数据包并非按照发送方的发送顺序和边界准确区分,多个数据包内容粘连在一起的现象 。比如发送方先后发送 “Hello” 和 “World” 两个数据包,接收方可能一次性收到 “HelloWorld” ,难以准确解析原始消息内容。
TCP 产生粘包的原因主要有:
- 发送端合并机制:发送端为提高传输效率,会采用策略合并小数据包。典型的 Nagle 算法,当发送方有未确认小数据包在网络传输时,新小数据包会被缓存,等确认后将缓存与新数据包合并发送。如传感器频繁发小数据,经 Nagle 算法可能合并成一个数据包发给服务器,引发粘包。
- 接收端读取延迟:接收端应用程序处理数据速度慢,TCP 接收缓冲区不断有新数据到达,若未及时读取,后续数据会与未读数据粘连,使接收端无法准确区分数据包边界。像文件传输中,客户端处理能力有限,不能及时处理接收数据,缓冲区数据积累,读取时可能就会出现粘包。
- 网络传输限制:IP 层分片重组可能导致数据合并。当应用层数据超最大传输单元(MTU),TCP 会分片传输,接收端需正确组装分片。若分片顺序错或丢失,可能导致粘包。另外,TCP 建立连接时双方协商的最大报文段长度(MSS)也有影响,数据超 MSS 会被拆分,接收端组装报文段出错也可能引发粘包 。
如何处理粘包现象?
应用层处理
- 固定格式法:给传输的数据加上固定格式,比如以特定字符作为开始符和结束符 。像发送数据 “Hello” 时,可在前后添加特殊字符,变为 “#Hello$” 。接收方在接收到数据后,依据特殊字符来判断数据包边界,解析出原始数据。不过要留意,数据内容里不能出现与特殊字符相同的字符,否则会干扰解析。
- 长度标识法:发送数据前,先告知接收方数据长度。常见做法是在数据头部设置固定字节数(如 4 字节)来表示后续真实数据的长度 。例如发送一段文本数据,先将文本长度用 4 字节表示并发送,接收方先读取这 4 字节,得知后续文本数据长度,再按此长度读取真实数据。
- 协议报头法:构建自定义协议报头,报头包含数据长度、数据类型等信息。发送时,先序列化报头(如用 JSON 等格式),再将报头长度、报头内容、真实数据依次发送。接收方先读报头长度,再根据长度读报头内容,解析报头获取数据信息后,按信息读真实数据。
发送方处理
- 关闭 Nagle 算法:Nagle 算法可能引发发送方粘包。在某些场景下,可通过设置
TCP_NODELAY选项关闭该算法,强制数据立即发送,避免小数据包合并,但这样会降低网络发送效率。 - 使用 push 操作指令:TCP 提供的 push 操作指令可让发送方不等待缓冲区满,直接发送本段数据,减少因缓冲区积攒数据导致的粘包,但也会一定程度影响传输效率优化。
接收方处理
- 优化程序设计:精简接收进程工作量,比如减少不必要的计算、磁盘 I/O 等操作,让接收进程能及时处理接收缓冲区的数据,降低粘包概率。
- 提高接收进程优先级:在操作系统层面提高接收进程优先级,使其能优先获取系统资源,及时从缓冲区读取数据,防止因处理不及时造成粘包 。
- 分包接收合并:接收方按数据结构字段,分多次接收一包数据再合并。比如接收包含多个字段的数据包,可按字段顺序依次接收并组装,但此方法会降低应用程序效率,不太适用于实时性要求高的场景。
TCP 与 UDP 的区别是什么,既然 TCP 是可靠的,那它有啥缺点 ⭐️⭐️ 重点
TCP(传输控制协议)与 UDP(用户数据报 协议)有以下区别:
-
连接方式
- TCP 是面向连接的协议,在数据传输之前,发送方和接收方需要先建立连接,就像打电话一样,需要先拨号接通,然后才能进行通话。
- UDP 是无连接的协议,发送方无需与接收方建立连接就可以直接发送数据,类似于写信,不需要事先通知对方就可以把信寄出去。
-
可靠性
- TCP 提供可靠的传输服务,通过序列号、确认应答、重传机制等保证数据的准确传输,能确保数据无差错、不丢失、不重复且按序到达。
- UDP 不保证数据的可靠传输,数据可能会丢失、重复或乱序到达,就像信件在邮寄过程中可能会丢失或延迟,但它也因此具有简单、高效的特点。
-
数据传输效率
- TCP 在传输数据时,需要进行连接建立、维护和断开等操作,并且有各种控制机制,所以传输效率相对较低。
- UDP 没有这些额外的操作和控制机制,数据传输效率较高,适合对实时性要求高、允许一定数据丢失的场景,如视频直播、实时游戏等。
-
数据格式
- TCP 是流式协议,数据像水流一样连续传输,没有明确的边界,需要应用层自己处理数据的边界问题,可能会出现粘包现象。
- UDP 是面向报文的协议,每个 UDP 数据包都有明确的边界,发送方发送的是一个个独立的报文,接收方也是以报文为单位进行接收。
虽然 TCP 是可靠的,但它也存在一些缺点:
- 传输效率相对较低:由于 TCP 为保证数据可靠性,有复杂的确认、重传等机制,在数据传输过程中会增加额外的开销,导致传输效率不如 UDP 高。特别是在一些网络环境较好、对数据准确性要求不是极高的场景下,这些额外开销可能会显得多余。
- 连接建立和维护开销大:TCP 连接的建立需要经过三次握手,连接的拆除需要经过四次挥手,这都需要消耗一定的时间和资源。在短连接的应用场景中,频繁地建立和拆除连接会带来较大的开销,影响系统性能。
- 对系统资源要求较高:TCP 需要在发送方和接收方维护连接状态信息,包括发送和接收缓冲区、序列号、确认号等,这需要占用一定的内存空间。当同时处理大量连接时,对系统的内存等资源要求较高,可能会成为系统性能的瓶颈。
- 实时性较差:因为 TCP 要保证数据的可靠传输和顺序性,当出现丢包或网络拥塞时,会进行重传和流量控制,这可能导致数据传输的延迟增加,不太适合对实时性要求极高的应用,如实时音视频通话,如果出现延迟会严重影响用户体验。
TCP与UDP的详细区别
头部开销
-
TCP:头部较大(至少20字节)
- 包含序列号、确认号、窗口大小、校验和等字段。
-
UDP:头部极小(仅8字节)
- 仅包含源端口、目的端口、长度和校验和。
典型协议
- TCP协议族:
- HTTP/HTTPS、FTP、SMTP、SSH、Telnet。
- UDP协议族:
- DNS、QUIC(HTTP/3底层协议)、RTP(实时传输协议)。
扩展对比表
| 特性 | TCP | UDP |
|---|---|---|
| 连接方式 | 面向连接(三次握手) | 无连接 |
| 应用场景 | 网页浏览(HTTP/HTTPS) | 实时音视频(Zoom、直播) |
| 可靠性 | 可靠(确认、重传、拥塞控制) | 不可靠(可能丢包、乱序) |
| 传输模式 | 字节流 | 数据报 |
| 传输效率 | 较低(高开销) | 极高(低开销) |
| 数据顺序 | 严格保证顺序 | 不保证顺序 |
| 头部大小 | 20~60字节 | 8字节 |
| 适用场景 | 数据完整性优先 | 实时性优先 |
如何选择协议?
-
选择TCP的情况:
- 需确保数据完整到达(如文件下载、网页加载)。
- 需按顺序处理数据(如数据库事务)。
-
选择UDP的情况:
- 实时性要求高于可靠性(如视频会议、语音通话)。
- 高频次小数据包传输(如传感器上报)。
高级应用:结合TCP与UDP的优势
- QUIC协议(HTTP/3的基础):
- 基于UDP实现,但内置了类似TCP的可靠性机制(
如丢包重传、拥塞控制)。 - 减少握手延迟(0-RTT连接建立),适合移动网络和高延迟环境。
- 基于UDP实现,但内置了类似TCP的可靠性机制(
总结
- TCP 是“可靠的信使”,适合对数据完整性要求高的场景。
- UDP 是“高效的快递员”,适合实时性和效率优先的应用。
- 实际开发中需根据业务需求权衡两者的特性,必要时可结合使用(如QUIC协议)。
TCP 的性能与机制考察
1. 为什么 TCP 有队头阻塞?
- TCP 是流式协议,数据必须按顺序到达,前面包未收到 → 后面包无法处理
2. 如何减少 TCP 连接建立开销?
- 使用
keep-alive - 启用 HTTP/2 多路复用
- 升级为 HTTP/3(使用 QUIC)
3. TCP 慢启动机制?
- 为防止拥塞,连接初期传输速率缓慢逐步升高
UDP 的典型应用考察
- 直播场景:使用 UDP 提高实时性,轻微丢包不影响观看
- 游戏通信:低延迟优先,逻辑冗余可容忍数据丢失
- DNS 查询:一次性请求,快速返回
- QUIC 协议:基于 UDP 实现的可靠传输,解决 TCP 队头阻塞问题
面试常见问题示例
| 问题 | 涉及知识点 |
|---|---|
| TCP 和 UDP 的区别? | 连接性、可靠性、效率、应用场景 |
| TCP 是如何保证数据可靠的? | 序列号、确认应答、超时重传、窗口机制 |
| TCP 为什么慢? | 建连握手、拥塞控制、重传机制 |
| UDP 丢包了怎么办? | 不处理,应用层自行容错或忽略 |
| HTTP/3 为什么用 UDP? | 避免 TCP 队头阻塞、提升连接建立速度 |
| WebSocket 基于 TCP 吗? | 是的,长连接场景依赖 TCP 的可靠性 |
关联面试题
TCP 传输过程?
- 连接建立:通过三次握手过程建立 TCP 连接。
- 数据传输:数据通过分段、确认、流量控制和拥塞控制机制传输。
- 连接终止:通过四次挥手过程终止 TCP 连接。
一个 tcp 连接能发几个 http 请求?
- HTTP/1.0:每个请求需要一个新的 TCP 连接。
- HTTP/1.1:一个 TCP 连接可以发多个请求,支持持久连接和管道化。
- HTTP/2:一个 TCP 连接可以并发发多个请求,通过多路复用技术优化性能。
- HTTP/3:基于 QUIC 协议,支持多个请求和响应在一个连接上进行。
TCP是怎么判断丢包的?
见 TCP 有哪些手段保证可靠交付 / TCP 为什么是可靠的
TCP/IP 是如何保证数据包传输有序可靠的?
见上
说说对TCP/IP协议的了解
- 应用层:提供应用程序间的通信,如SMTP、FTP、Telnet等。
- 传输层:负责数据格式化、数据确认和丢失重传等,包括TCP和UDP。
- 网络层:提供基本的数据封包传送功能,如IP协议。
- 数据链路层:负责接收IP数据报并进行传输,管理网络媒体,如Ethernet、Serial Line等。
DNS 解析过程

DNS(Domain Name System,域名系统)解析是将域名或主机名转换为 IP 地址的过程,以便计算机能够在网络中找到目标服务器。以下是 DNS 解析的一般过程:
-
缓存查询:
- 查本地的 DNS 缓存
- 向 DNS 服务器发起查询,直到找到对应的 IP 地址
-
递归查询:
- 本地 DNS服务 → 根 DNS → 顶级 DNS(如 .com) → 权威 DNS(如 example.com)
网络延迟和丢包
在前端面试中,网络延迟和丢包是评估你对网络传输、性能瓶颈及应对策略理解的重要考点。面试官会通过这些话题判断能否从网络层面分析问题、优化用户体验,特别是在弱网环境、移动端场景下。
一、网络延迟的考点
1. 网络延迟的构成
面试官可能会问:“用户输入 URL 后,请求延迟可能发生在哪些阶段?”
| 阶段 | 含义 |
|---|---|
| DNS 解析 | 域名 → IP 地址 |
| TCP 建立连接 | 三次握手耗时 |
| TLS 握手 | HTTPS 建立安全连接耗时 |
| 请求发送 | 客户端发送数据 |
| 首字节返回 TTFB | 服务端处理 + 网络传输 |
| 内容下载 | 响应内容下载耗时 |
| 渲染耗时 | 浏览器解析和绘制页面 |
2. 常见影响网络延迟的因素
- 地域距离:客户端与服务端物理距离大(如中国访问美国服务器)
- DNS 缓存未命中或 DNS 配置不合理
- TLS 握手过长(HTTPS 开销)
- 带宽瓶颈:文件过大、网络拥堵
- 长连接未复用(未启用 HTTP/2)
- 移动网络抖动高(4G/5G 网络波动)
- 首包延迟(TTFB 过高)
3. 如何优化延迟?
- 启用 CDN,部署全球节点,减少 RTT
- 启用 DNS 预解析:
<link rel="dns-prefetch"> - 启用 HTTP/2 或 HTTP/3,减少连接耗时
- 减少重定向跳转、合并请求
- 使用
preconnect、prefetch提前连接目标源 - SSR 提前输出首屏 HTML,减少白屏
- 缓存优化(减少服务端响应压力)
二、丢包的考点
1. 丢包的本质
网络传输中,部分数据包因链路拥堵、信号弱、硬件丢包率高等原因,未能到达目的地。
TCP:自动重传(影响性能) UDP:直接丢弃(不保证可靠)
2. 丢包导致的问题
- 加载失败:资源文件加载中断(如 JS/CSS/图片)
- 响应延迟:TCP 重传机制 → 等待时间增加
- 交互卡顿:重要请求(如接口)多次丢失
- 视频/音频卡顿:UDP 传输音视频,丢包率影响体验
3. 如何应对丢包?
- 使用 HTTP/3(QUIC) :基于 UDP,内建重传 + 多路复用,丢包影响小
- 合理设置超时重试机制:接口请求失败时自动重试
- 请求兜底策略:核心数据失败后提示用户或降级
- 断点续传/Range 请求:大文件支持分段传输
- 服务端压缩:减少包体积,降低丢包概率
- 尽量使用 CDN:就近分发,避免跨境链路
三、典型面试问题示例
| 问题 | 涉及知识点 |
|---|---|
| TTFB 高可能有哪些原因? | DNS 慢、服务器响应慢、TLS 握手慢 |
| 如何应对弱网环境下的资源丢包? | 重试机制、HTTP/3、断点续传 |
| TCP 丢包和 UDP 丢包的区别? | TCP 重传保证可靠性,UDP 丢就丢了 |
| 为什么 HTTP/3 更适合移动端? | 快速建连、UDP、丢包影响小 |
| 如果某请求丢包导致加载卡顿,怎么定位? | DevTools 网络请求状态、失败重试、ping/traceroute |
四、总结表格
| 项目 | 网络延迟 | 丢包 |
|---|---|---|
| 本质 | 请求往返耗时(RTT) | 网络数据包未能到达 |
| 表现 | 页面加载慢、白屏、交互延迟 | 请求失败、加载中断、视频卡顿 |
| 影响范围 | 所有请求均可能影响 | 重要资源或关键请求影响更明显 |
| 优化方式 | CDN、预连接、HTTP/2、请求合并等 | QUIC 协议、请求重试、兜底机制 |
| 与协议关系 | TCP/UDP 均有延迟 | TCP 可重传,UDP 丢包不可恢复 |
| 工具定位 | Chrome DevTools、ping、traceroute | DevTools 网络失败、Wireshark |
关联面试题
网络延迟和丢包
在前端面试中,网络延迟和丢包是评估你对网络传输、性能瓶颈及应对策略理解的重要考点。面试官会通过这些话题判断能否从网络层面分析问题、优化用户体验,特别是在弱网环境、移动端场景下。
一、网络延迟的考点
1. 网络延迟的构成
面试官可能会问:“用户输入 URL 后,请求延迟可能发生在哪些阶段?”
| 阶段 | 含义 |
|---|---|
| DNS 解析 | 域名 → IP 地址 |
| TCP 建立连接 | 三次握手耗时 |
| TLS 握手 | HTTPS 建立安全连接耗时 |
| 请求发送 | 客户端发送数据 |
| 首字节返回 TTFB | 服务端处理 + 网络传输 |
| 内容下载 | 响应内容下载耗时 |
| 渲染耗时 | 浏览器解析和绘制页面 |
2. 常见影响网络延迟的因素
- 地域距离:客户端与服务端物理距离大(如中国访问美国服务器)
- DNS 缓存未命中或 DNS 配置不合理
- TLS 握手过长(HTTPS 开销)
- 带宽瓶颈:文件过大、网络拥堵
- 长连接未复用(未启用 HTTP/2)
- 移动网络抖动高(4G/5G 网络波动)
- 首包延迟(TTFB 过高)
3. 如何优化延迟?
- 启用 CDN,部署全球节点,减少 RTT
- 启用 DNS 预解析:
<link rel="dns-prefetch"> - 启用 HTTP/2 或 HTTP/3,减少连接耗时
- 减少重定向跳转、合并请求
- 使用
preconnect、prefetch提前连接目标源 - SSR 提前输出首屏 HTML,减少白屏
- 缓存优化(减少服务端响应压力)
二、丢包的考点
1. 丢包的本质
网络传输中,部分数据包因链路拥堵、信号弱、硬件丢包率高等原因,未能到达目的地。
TCP:自动重传(影响性能) UDP:直接丢弃(不保证可靠)
2. 丢包导致的问题
- 加载失败:资源文件加载中断(如 JS/CSS/图片)
- 响应延迟:TCP 重传机制 → 等待时间增加
- 交互卡顿:重要请求(如接口)多次丢失
- 视频/音频卡顿:UDP 传输音视频,丢包率影响体验
3. 如何应对丢包?
- 使用 HTTP/3(QUIC) :基于 UDP,内建重传 + 多路复用,丢包影响小
- 合理设置超时重试机制:接口请求失败时自动重试
- 请求兜底策略:核心数据失败后提示用户或降级
- 断点续传/Range 请求:大文件支持分段传输
- 服务端压缩:减少包体积,降低丢包概率
- 尽量使用 CDN:就近分发,避免跨境链路
三、典型面试问题示例
| 问题 | 涉及知识点 |
|---|---|
| TTFB 高可能有哪些原因? | DNS 慢、服务器响应慢、TLS 握手慢 |
| 如何应对弱网环境下的资源丢包? | 重试机制、HTTP/3、断点续传 |
| TCP 丢包和 UDP 丢包的区别? | TCP 重传保证可靠性,UDP 丢就丢了 |
| 为什么 HTTP/3 更适合移动端? | 快速建连、UDP、丢包影响小 |
| 如果某请求丢包导致加载卡顿,怎么定位? | DevTools 网络请求状态、失败重试、ping/traceroute |
四、总结表格
| 项目 | 网络延迟 | 丢包 |
|---|---|---|
| 本质 | 请求往返耗时(RTT) | 网络数据包未能到达 |
| 表现 | 页面加载慢、白屏、交互延迟 | 请求失败、加载中断、视频卡顿 |
| 影响范围 | 所有请求均可能影响 | 重要资源或关键请求影响更明显 |
| 优化方式 | CDN、预连接、HTTP/2、请求合并等 | QUIC 协议、请求重试、兜底机制 |
| 与协议关系 | TCP/UDP 均有延迟 | TCP 可重传,UDP 丢包不可恢复 |
| 工具定位 | Chrome DevTools、ping、traceroute | DevTools 网络失败、Wireshark |
DNS劫持

DNS 劫持,又称为域名劫持,是一种恶意行为,指的是攻击者通过各种手段篡改域名系统(DNS)的正常解析过程,使得用户在访问特定域名时被引导到错误的 IP 地址,从而可能导致用户访问到虚假网站、遭受信息泄露等安全问题。
工作原理
- 篡改 DNS 服务器记录:攻击者通过入侵 DNS 服务器,直接修改服务器上的域名解析记录。例如,将正常的银行网站域名解析到一个钓鱼网站的 IP 地址,当用户访问银行网站时,就会被误导到钓鱼网站。
- 拦截 DNS 查询请求:在用户的设备与 DNS 服务器之间的通信过程中,攻击者利用中间人攻击等方式拦截 DNS 查询请求,并返回虚假的响应,将用户引导到错误的网站。
危害
- 信息泄露:用户可能在不知情的情况下将个人敏感信息,如账号密码、身份证号码等输入到虚假网站上,导致信息被攻击者窃取,进而造成经济损失和个人隐私泄露。
- 恶意软件传播:用户被引导到恶意网站后,可能会自动下载并安装恶意软件,如病毒、木马等,这些恶意软件会进一步感染用户的设备,窃取更多信息或控制用户的设备。
防范措施
- 使用可靠的 DNS 服务:选择信誉良好、安全可靠的 DNS 服务提供商,如谷歌公共 DNS、OpenDNS 等,或者使用运营商提供的默认 DNS 服务,并及时关注 DNS 服务提供商的安全公告,以获取最新的安全防护信息。
- 安装安全软件:在设备上安装杀毒软件、防火墙等安全软件,这些软件可以检测和防范部分 DNS 劫持攻击,实时监控网络流量,发现异常的 DNS 请求和响应,并进行拦截和处理。
- 定期更新系统和软件:及时更新操作系统、浏览器、DNS 服务器软件等,以修复可能存在的安全漏洞,降低被攻击的风险。
DNS 安全考察
| 威胁 | 说明 |
|---|---|
| DNS 劫持 | 恶意篡改解析结果,用户被引导至假冒网站 |
| DNS 投毒 | 缓存伪造 IP,污染 DNS 服务器结果 |
| 防护措施 | 使用 DNSSEC(域名系统安全扩展)验证响应签名;启用 HTTPS-DNS(DoH/DoT)加密 DNS 查询 |
| DoH(DNS over HTTPS) | 将 DNS 查询通过 HTTPS 发送,防止被监听或篡改 |
DNS 缓存机制考察
| 缓存位置 | 特点 |
|---|---|
| 浏览器缓存 | 优先读取,缓存时间受 DNS TTL 控制 |
| 系统缓存 | 如 macOS 的 dscacheutil、Windows 的 DNS 缓存 |
| 本地 DNS 缓存 | 运营商提供,缓存命中高,减少外部请求 |
相关字段:
- TTL(Time To Live) :DNS 记录生存时间,影响缓存有效期
DNS 查询性能优化(常考)
| 技术/策略 | 说明 |
|---|---|
| DNS 预获取 | <link rel="dns-prefetch" href="//example.com">,提前解析域名 |
| preconnect | <link rel="preconnect" href="https://example.com">,提前建立连接(包括 DNS + TCP + TLS) |
| 缓存优化 | 提高 DNS TTL,减少频繁解析(TTL(Time To Live) :DNS 记录生存时间,影响缓存有效期) |
| 合理分域名访问资源 | 避免过多不同域名导致 DNS 查询阻塞 |
DNS 与前端的关联考察点
| 关联方向 | 说明 |
|---|---|
| 页面首次加载慢 | 可能由于 DNS 查询时间长,可使用 performance.getEntriesByType('resource') 检查 DNS 时间 |
| 域名切换带来的缓存失效 | 资源域名变化会触发新的 DNS 查询和重新建立连接 |
| 第三方资源加载慢 | 如字体、CDN、图标等域名没有预解析 |
| CNAME、CDN 解析过程 | CDN 域名背后也可能经过多次 DNS 跳转解析 |
面试常见问题示例
| 问题 | 涉及考点 |
|---|---|
| DNS 是什么?为什么需要它? | 基础原理 |
| DNS 查询的完整流程是怎样的? | 缓存、递归与迭代查询 |
| DNS 查询用的是哪个协议? | UDP(53 端口)为主 |
| 浏览器如何优化 DNS 性能? | DNS 预获取、预连接 |
| 什么是 DNS 劫持?如何防止? | 安全考察 |
| DNS TTL 的作用? | 缓存机制与刷新间隔 |
| 为什么首次加载慢?如何判断是 DNS 问题? | 前端性能分析工具使用 |
WebSocket常见考点
WebSocket 是常考的实时通信技术,面试官通常会从其原理、与 HTTP 的关系、使用方式、应用场景、安全性、性能优化等方向进行考察。以下是系统整理的 WebSocket 考察点大全:
一、基础概念考察
| 考察点 | 要点 |
|---|---|
| WebSocket 是什么? | 是一种基于 TCP 的全双工通信协议,用于客户端与服务端建立持久连接 |
| 解决了什么问题? | 解决了 HTTP 无法实现真正实时通信、轮询/长轮询开销大的问题 |
| 属于哪一层协议? | 基于 TCP 之上的应用层协议,协议名称是 ws://(或加密的 wss://) |
二、与 HTTP 的关系
| 考察点 | 要点 |
|---|---|
| 如何建立连接? | 使用 HTTP 协议的 Upgrade 机制 进行握手,成功后协议变为 WebSocket |
| 建立连接过程 | 客户端发起包含 Upgrade: websocket 的请求,服务端返回 101 Switching Protocols |
| 与 HTTP 的区别 | HTTP 是 单向请求响应,WebSocket 是 双向持续通信 |
| 与 HTTP/2 的区别 | WebSocket 不能直接复用 HTTP/2,需要独立连接 |
三、使用与 API 考察
| 考察点 | 要点 |
|---|---|
| WebSocket 创建方式 | const socket = new WebSocket('ws://example.com') |
| 常用事件 | onopen、onmessage、onclose、onerror |
| 发送数据 | socket.send(data) |
| 关闭连接 | socket.close(code, reason) |
| 消息格式 | 支持字符串、Blob、ArrayBuffer 等格式 |
四、应用场景考察
| 场景 | 原因 |
|---|---|
| 实时聊天、弹幕、在线游戏 | 高实时性,低延迟 |
| 股票、彩票、竞价系统 | 实时数据推送 |
| 协同编辑(如在线文档) | 多端状态同步 |
| 物联网设备通讯 | 双向通信能力 |
五、与其他通信方案对比
| 特性 | HTTP 轮询 | SSE(Server-Sent Events) | WebSocket |
|---|---|---|---|
| 双向通信 | 否 | 否 | ✅ 是 |
| 单连接复用 | ❌ 否 | ✅ 是(只接收) | ✅ 是(双向) |
| 延迟性能 | 高 | 中 | ✅ 低(最快) |
| 浏览器兼容性 | ✅ 普遍支持 | 部分旧版 IE 不支持 | ✅ 普遍支持 |
| 断线重连 | ❌ 需手动实现 | ✅ 内建支持 | ❌ 需手动实现或封装处理 |
这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。我们只能使用"轮询":每隔一段时候,就发出一个询问,了解服务器有没有新的信息。最典型的场景就是聊天室。轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。
在 WebSocket 协议出现以前,创建一个和服务端进双通道通信的 web 应用,需要依赖HTTP协议,进行不停的轮询,这会导致一些问题:
- 服务端被迫维持来自每个客户端的大量不同的连接
- 大量的轮询请求会造成高开销,比如会带上多余的header,造成了无用的数据传输。
http协议本身是没有持久通信能力的,但是我们在实际的应用中,是很需要这种能力的,所以,为了解决这些问题,WebSocket协议由此而生,于2011年被IETF定为标准RFC6455,并被RFC7936所补充规范。
并且在HTML5标准中增加了有关WebSocket协议的相关api,所以只要实现了HTML5标准的客户端,就可以与支持WebSocket协议的服务器进行全双工的持久通信了。
六、断线重连与心跳机制
考察点
-
为什么需要心跳? → 检测客户端是否在线,防止中间网络断开但不通知。
-
如何实现?
- 客户端定时发送
"ping"或自定义心跳包 - 服务端超时未收到则断开连接
- 客户端定时发送
-
断线重连策略
- 实现自动重连(如指数退避重连)
- 避免频繁重连导致服务器压力过大
七、安全性考察
| 考察点 | 要点 |
|---|---|
| 加密版本 | 使用 wss://(相当于 HTTPS),基于 TLS 加密 |
| 身份认证 | 一般通过握手时携带 token/cookie 完成认证 |
| 跨域支持 | 默认支持跨域(同源限制不严格) |
| 被动关闭连接 | 网络断开、浏览器关闭页面、服务器断开 |
| DoS 防护 | 服务端需做连接数限制和身份验证,防止连接滥用 |
八、服务端实现方案(了解为加分项)
| 技术 | 特点 |
|---|---|
| Node.js + ws | 简单、适合轻量服务 |
| Socket.io | 封装了 WebSocket,支持断线重连、fallback、事件系统 |
| Go / Java / Python | 多种语言有成熟框架 |
九、面试常见问题示例
| 问题 | 考察方向 |
|---|---|
| WebSocket 如何建立连接? | 握手流程、Upgrade |
| WebSocket 与 HTTP 的区别? | 通信模式、连接状态 |
| WebSocket 有哪些使用场景? | 实时应用、双向通信 |
| 如何处理 WebSocket 的断线重连? | 重连机制、心跳包 |
| WebSocket 如何鉴权? | 握手参数、token 认证 |
| WebSocket 与 SSE 有何区别? | 单向 vs 双向、兼容性 |
关联面试题
WebSocket协议的底层原理、与HTTP的区别
WebSocket 协议底层原理
WebSocket 协议的核心目标是在浏览器和服务器之间建立持久的、全双工的通信连接,其底层原理可从以下几个阶段来理解:
1. 握手阶段
-
客户端发起请求:客户端通过发送一个特殊的 HTTP 请求到服务器,请求将当前的 HTTP 连接升级为 WebSocket 连接。这个请求的 HTTP 头中包含了一些关键信息,例如:
Upgrade: websocket:表明客户端希望将协议升级为 WebSocket。Connection: Upgrade:表示要进行协议升级。Sec - WebSocket - Key:是一个经过 Base64 编码的随机值,用于验证服务器响应的合法性。Sec - WebSocket - Version:指定了客户端支持的 WebSocket 版本。
-
服务器响应:服务器接收到请求后,会对请求头进行检查。如果服务器支持 WebSocket 协议,就会返回一个状态码为
101 Switching Protocols的 HTTP 响应,表示同意升级连接。响应头中也包含了一些关键信息:Upgrade: websocket和Connection: Upgrade:确认协议升级。Sec - WebSocket - Accept:是服务器根据客户端发送的Sec - WebSocket - Key计算得出的值,用于客户端验证服务器响应的合法性。
2. 数据传输阶段
- 帧格式:握手成功后,连接就从 HTTP 升级为 WebSocket,数据以帧(Frame)的形式在客户端和服务器之间传输。每个 WebSocket 帧包含一个帧头和一个帧体。
- 全双工通信:客户端和服务器可以在这个连接上独立地、同时地发送和接收数据,实现了真正的全双工通信。双方无需等待对方的响应就可以随时发送新的数据。
3. 关闭连接阶段
- 发送关闭帧:当一方希望关闭连接时,会发送一个关闭帧给对方。关闭帧中包含了关闭的状态码和可选的关闭原因。
- 响应关闭帧:另一方收到关闭帧后,通常会发送一个确认关闭帧作为响应,然后双方关闭底层的 TCP 连接。
WebSocket 与 HTTP 的区别
1. 连接特性
- HTTP:无状态的、短连接协议。每次客户端向服务器发送请求时,都需要建立一个新的 TCP 连接,请求处理完成后,连接就会关闭。这意味着每次请求都需要重新进行 TCP 握手,开销较大。
- WebSocket:有状态的、长连接协议。在握手成功后,连接会一直保持打开状态,直到一方主动关闭。这避免了频繁建立和关闭连接的开销,提高了通信效率。
2. 通信模式
- HTTP:半双工通信,同一时间内数据
只能单向传输,要么是客户端向服务器发送请求,要么是服务器向客户端发送响应。客户端必须等待服务器的响应后才能发起新的请求。 - WebSocket:全双工通信,客户端和服务器可以同时向对方发送数据,实现了实时的双向通信,无需等待对方的响应。
3. 数据传输效率
- HTTP:每次请求和响应都需要携带完整的 HTTP 头信息,即使传输的数据量很小,也会有较大的额外开销。而且HTTP 请求和响应通常是基于文本的,传输效率相对较低。
- WebSocket:在握手阶段后,数据传输只需要包含少量的帧头信息,减少了额外开销。同时,WebSocket 支持二进制数据传输,对于一些需要传输大量数据的场景(如视频、音频等),效率更高。
4. 应用场景
- HTTP:适用于传统的 Web 页面请求、文件下载等场景,主要用于一次性的请求 - 响应交互。
- WebSocket:更适合实时性要求高的场景,如在线聊天、实时数据推送(如股票行情、实时天气预报等)、多人游戏、实时监控等。
详细讲解WebSocket协议
1. WebSocket的本质
- 双向实时通信协议:与HTTP的"请求-响应"模式不同,WebSocket建立持久化全双工连接,支持服务端主动推送数据。
- 协议升级机制:通过HTTP握手(Upgrade头)切换到WebSocket协议(
ws://或wss://)。 - 低延迟传输:基于TCP,但避免HTTP头重复传输,减少数据包体积。
2. 关键优势
| 特性 | 传统HTTP | WebSocket |
|---|---|---|
| 连接模式 | 短连接,单向请求 | 长连接,双向通信 |
| 头部开销 | 每次请求携带完整Header | 初始握手后仅传输数据帧 |
| 实时性 | 依赖轮询(高延迟) | 毫秒级推送 |
| 服务器主动推送 | 不支持 | 原生支持 |
| 适用场景 | 静态资源获取 | 实时交互应用 |
与替代方案对比
| 技术 | 协议 | 方向 | 复杂度 | 适用场景 |
|---|---|---|---|---|
| WebSocket | TCP | 双向 | 中 | 实时双向交互 |
| SSE | HTTP | 单向 | 低 | 服务端到客户端推送 |
| 长轮询 | HTTP | 半双工 | 高 | 兼容性要求高的场景 |
| WebRTC | UDP | 双向 | 高 | 音视频流传输 |
WebSocket已成为现代实时Web应用的基石技术,日均处理数十亿连接。掌握其原理和最佳实践,是构建高性能实时系统的关键能力。
介绍一下 Service Worker ⭐️⭐️
service worker是PWA的重要组成部分,W3C 组织早在 2014 年 5 月就提出过 Service Worker 这样的一个 HTML5 API ,主要用来做持久的离线缓存,也是Web Worker的升级版。
Service worker (简称 SW) 是一个注册在指定源和路径下的事件驱动 Worker。它采用 JavaScript 控制关联的页面或者网站,拦截并修改访问和资源请求,细粒度地缓存资源。你可以完全控制应用在特定情形(最常见的情形是网络不可用)下的表现。
定义与作用
- 后台脚本:Service Worker是浏览器后台独立于主线程之外的工作线程。
- 网络代理:可拦截和处理网络请求,资源缓存,离线访问。
- 事件驱动:响应推送通知、后台同步等事件,增强Web应用功能。
Service Worker 的缓存机制是通过缓存 API 实现的,它允许开发者拦截和缓存 HTTP 请求,以提高离线体验和加速页面加载。以下是 Service Worker 缓存 HTTP 请求资源的基本流程和原理:
1. 注册 Service Worker
首先,Service Worker 需要在浏览器中注册。通常在主线程(如 JavaScript 入口文件)中进行注册:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('Service Worker registered with scope:', registration.scope);
})
.catch(error => {
console.error('Service Worker registration failed:', error);
});
}
2. 安装 Service Worker
在 Service Worker 脚本中,首先会触发 install 事件。在这个事件中,可以预缓存一些资源,以便在 Service Worker 激活后立即可用:
self.addEventListener('install', event => {
event.waitUntil(
caches.open('my-cache-v1').then(cache => {
return cache.addAll([
'/',
'/styles/main.css',
'/scripts/main.js',
'/images/logo.png'
]);
})
);
});
3. 激活 Service Worker
activate 事件在 Service Worker 安装完成后触发。可以在这个事件中进行缓存清理,删除旧的缓存:
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.filter(cacheName => {
// 这里可以指定要删除的缓存
return cacheName !== 'my-cache-v1';
}).map(cacheName => {
return caches.delete(cacheName);
})
);
})
);
});
4. 拦截和缓存请求
fetch 事件允许 Service Worker 拦截所有的网络请求。可以根据需要从缓存中返回资源,或将请求转发到网络:
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(cachedResponse => {
// 如果缓存中有匹配的资源,直接返回
if (cachedResponse) {
return cachedResponse;
}
// 否则,发起网络请求
return fetch(event.request).then(response => {
// 克隆响应对象,因为响应只能被消费一次
const responseClone = response.clone();
// 将网络请求的结果缓存
caches.open('my-cache-v1').then(cache => {
cache.put(event.request, responseClone);
});
return response;
});
}).catch(() => {
// 网络和缓存都失败的情况
return new Response('Oops, something went wrong.');
})
);
});
5. 资源管理
- 缓存清理:定期删除过期或不再需要的缓存,保持缓存的健康状态。
- 缓存策略:可以实现不同的缓存策略,如缓存优先、网络优先、缓存和网络同时等。
Web Workers常见考点
1. Web Workers 的基本概念
- 定义:Web Workers 是运行在后台的独立线程,允许在不阻塞主线程的情况下执行脚本代码。
- 类型:常见的有 Dedicated Workers(专用 Workers,单页面使用)和 Shared Workers(共享 Workers,多个页面或同源脚本共享)。
2. 如何创建和使用 Web Worker
-
Worker 创建:
- 通过
new Worker()创建 Worker 线程,传入一个 JavaScript 文件的路径作为参数。
const worker = new Worker('worker.js'); - 通过
-
消息通信:
- 主线程通过
postMessage()向 Worker 发送消息,Worker 通过onmessage事件处理消息并返回处理结果:
// 主线程 worker.postMessage('Hello Worker!'); worker.onmessage = function(event) { console.log('Received from worker:', event.data); }; // worker.js self.onmessage = function(event) { console.log('Received from main thread:', event.data); self.postMessage('Message received'); }; - 主线程通过
3. Web Workers 的特性
- 异步执行:Web Workers 运行在独立线程中,与主线程并行,不会阻塞主线程的 UI 渲染或事件处理。
- 不共享上下文:Worker 没有访问 DOM、window、document 等浏览器对象的权限,运行在独立的全局作用域中(
self对象)。 - 通信机制:主线程与 Worker 通过
postMessage()传递消息,消息是通过串行化传递的,数据不会共享,而是复制。 - 支持的 API:Worker 支持的 API 有
XMLHttpRequest、fetch、setTimeout、setInterval、WebSockets、importScripts(),但不支持 DOM 操作。
4. Web Workers 的使用场景
- CPU 密集型任务:如复杂的数学计算、大量数据处理、图片和视频处理等,可以放到 Worker 中执行,避免主线程被阻塞。
- 异步数据处理:如后台处理 API 响应、大型 JSON 解析、加密解密等任务,保证 UI 的流畅性。
- 离线应用中的数据同步:通过 Web Workers 处理离线数据的同步与缓存,保证数据一致性。
5. Web Workers 与多线程的区别
- Worker 是单线程的:每个 Web Worker 是独立的单线程,多个 Worker 可以并行执行任务,但 Worker 本身并没有真正的多线程能力 (不会共享状态)。
- 多 Worker 协作:可以通过创建多个 Worker 实现伪多线程,通过消息传递共享数据。
6. Shared Worker 的特点
- 共享 Worker 线程:不同的浏览器窗口、iframe 等在同一页面中可以共享一个 Worker 线程,适用于跨多个页面协作的场景。
- 通信方式:与专用 Worker 类似,但不同页面之间可以通过
MessagePort进行通信。
7. Worker 中的错误处理
- 主线程错误处理:主线程可以通过
onerror事件捕获 Worker 中的错误。
worker.onerror = function(error) {
console.log('Error in worker:', error.message);
};
- Worker 内的错误捕获:Worker 内部可以使用 try-catch 捕获代码执行中的错误。
8. Web Workers 的生命周期管理
- 终止 Worker:可以通过**
terminate()**方法在主线程中手动终止 Worker。
worker.terminate();
- 自动销毁:Worker 执行完成后不会自动销毁,仍然可以保持活跃等待进一步的消息,因此需要手动管理 Worker 的生命周期以释放资源。
9. Web Workers 的性能优化
- 线程开销:创建 Worker 线程有一定的开销,过多的 Worker 可能会增加性能负担,尤其是在短时间内频繁创建和销毁 Worker 的场景。
- 消息传递的成本:由于消息是通过拷贝传递的,大量数据传递会带来性能开销。可以通过使用 Transferable Objects 来优化数据传输。
10. Transferable Objects
- 特点:Transferable Objects 允许直接将数据的所有权转移给 Worker,而不是复制数据。常用于 ArrayBuffer 等大数据传输的场景,提升性能。
let buffer = new ArrayBuffer(1024);
worker.postMessage(buffer, [buffer]);
11. Service Workers 与 Web Workers 的区别
- 作用不同:Web Workers 用于在后台执行计算密集型任务,主要是数据处理;Service Workers 则用于控制网络请求、缓存管理、离线支持等。
- 生命周期不同:Service Workers 在用户首次访问页面时注册后一直存在,即使关闭页面也能继续运行;而 Web Workers 只在页面活跃时存在。
12. Web Workers 的兼容性
- 需要了解 Web Workers 在不同浏览器中的兼容性,尤其是在移动端或旧版本浏览器中的支持情况。
13. Worker 线程中的模块化脚本加载
- importScripts() :Web Workers 支持使用
importScripts()同步加载外部脚本,考察点可能包括如何使用该方法来分割代码或动态加载代码。
importScripts('script1.js', 'script2.js');
14. Worker 内的 API 支持
- 支持的 API:如 Web Workers 支持的部分 API(如
fetch、WebSockets、setTimeout、XMLHttpRequest),如何在 Worker 内使用这些 API。 - 不支持的 API:如 DOM 操作、
alert()等不支持的操作,考察点可能包括 Worker 的使用限制。
关联面试题
WebWorker、SharedWorker 和 ServiceWorker 有哪些区别?
正向代理和反向代理常见考点
“正向代理”和“反向代理”是前端与网络交叉领域的高频考察点,涉及网络请求过程、安全控制、架构设计、前端跨域处理等多个方面。
一、基础定义(核心区别)
| 类型 | 代理对象 | 作用方位 | 用户是否感知 |
|---|---|---|---|
| 正向代理 | 客户端 → 服务端 | 客户端访问外部资源 | 是 |
| 反向代理 | 服务端 → 客户端 | 服务端代理多个后端 | 否 |
二、举例理解
-
正向代理:你无法直接访问被墙的
google.com,通过代理服务器proxy.com访问,proxy.com再去请求google.com并返回结果给你。- 常用于:翻墙、隐匿用户身份、访问受限资源
-
反向代理:你访问
api.example.com,请求先到反向代理服务器(如 Nginx),再转发到真正的后端服务(如node1.internal)。- 常用于:负载均衡、缓存、统一鉴权、隐藏服务结构
三、典型面试考察点
1. 正向代理考察点
| 点位 | 要点 |
|---|---|
| 作用 | 客户端通过代理访问目标资源 |
| 应用场景 | 翻墙、匿名访问、突破访问限制(如公司内网限制访问外网) |
| 原理 | 客户端将目标地址请求发给代理 → 代理向目标服务器请求 → 返回结果给客户端 |
| 实现方式 | 浏览器配置代理地址,或使用程序设置代理 |
| 安全性 | 会暴露目标地址,用户身份可能被记录 |
2. 反向代理考察点
| 点位 | 要点 |
|---|---|
| 作用 | 客户端访问代理服务器,由代理向真实服务请求 |
| 应用场景 | 负载均衡、服务聚合、缓存加速、安全防护、隐藏内部服务 |
| 原理 | 客户端只知道代理地址,代理内部根据路径、策略转发请求 |
| 实现方式 | 使用** Nginx、Apache、Node.js** 等配置反向代理规则 |
| 安全性 | 屏蔽真实服务地址,方便统一鉴权和防护(如 DDOS) |
四、与前端的关系
| 考察方向 | 说明 |
|---|---|
| 跨域处理 | 本地开发环境通过 devServer.proxy 或 Nginx 设置反向代理 → 绕过 CORS |
| 资源访问加速 | 前端资源或 API 接口通过反向代理 CDN/缓存节点加速 |
| 统一接口转发 | 前端请求统一发给一个网关地址,网关做反向代理路由分发 |
| SSR 渲染 | 前端请求 SSR 服务 → 反向代理渲染结果页面返回 |
五、常见面试问题
| 面试问题 | 涉及知识点 |
|---|---|
| 正向代理和反向代理的区别? | 代理方向、用户是否感知、应用场景 |
| 为什么前端开发时使用反向代理可以解决跨域问题? | 跨域绕过原理、同源策略 |
| 如何使用 Nginx 设置反向代理? | Nginx 配置规则 |
| 服务端如何实现接口聚合? | 反向代理网关分发请求 |
| 如何隐藏真实服务地址? | 利用反向代理统一出口 |
| CDN 是正向代理还是反向代理? | 反向代理(常考陷阱题) ,CDN 面向用户,但代理的是服务器资源 |
六、配套场景理解
-
Nginx 配置反向代理示例:
location /api/ { proxy_pass http://backend-server/; proxy_set_header Host $host; } -
Webpack DevServer 开发时的代理设置(前端 CORS 绕过):
devServer: { proxy: { '/api': { target: 'http://localhost:3000', changeOrigin: true, }, } }
七、扩展考点
| 扩展点 | 说明 |
|---|---|
| CDN 是否属于代理 | 属于反向代理(缓存 + 加速) |
| 网关与反向代理的区别 | 网关具备更强的逻辑、鉴权、路由能力 |
| 微服务架构中反向代理的作用 | 服务聚合、统一入口、灰度发布等 |
| TLS 终止代理 | Nginx 处理 SSL,后端走明文 HTTP,简化后端服务配置 |
关联面试题
网络性能优化常见考点
前端“网络层面的性能优化”是高频面试考点,涵盖了从资源加载、缓存、连接管理,到协议选择等多个方向。面试时往往从“用户输入 URL 到页面加载”这条链路入手,考查在网络传输环节提升页面性能的能力。
1. DNS 优化
- 使用 DNS 预解析(
<link rel="dns-prefetch">) - 减少跨域请求
- 使用 CDN 降低解析延迟
- 减少 DNS 查询频次(共享域名)
2. TCP/TLS 连接优化
- 连接复用(Keep-Alive、HTTP/2 多路复用)
- 减少重定向次数
- 减少第三方域名连接数(避免多次三次握手)
- TLS1.3 优化握手过程
3. HTTP 协议优化
-
使用 HTTP/2:
- 多路复用(消除队头阻塞)
- 头部压缩
- Server Push(预加载资源)
-
使用 HTTP/3:
- 基于 QUIC,减少握手延迟
4. 缓存策略优化
- 强缓存:
Cache-Control: max-age、Expires - 协商缓存:
ETag/Last-Modified - CDN 缓存策略
- 静态资源使用 hash 文件名(内容变动才刷新)
5. 资源加载优化
-
懒加载:图片、视频等资源按需加载(
loading="lazy") -
预加载 & 预请求:
<link rel="preload"><link rel="prefetch">
-
按需加载模块(JS/CSS)
6. 压缩与传输优化
- 启用 Gzip 或 Brotli 压缩文本资源
- 图片压缩优化(WebP、AVIF)
- 雪碧图、SVG 精简、字体子集
- 减少重复包体(第三方库抽离 CDN)
7. 请求合并与去重
- 合并资源:CSS、JS 打包合并(仅适用于 HTTP/1.1)
- 使用图标字体 / 雪碧图减少请求
- GraphQL 替代多个 REST 请求
8. 首屏优化
- 关键资源优先加载(CSS、字体、JS)
- SSR + Hydration 提高 TTFB
- Skeleton + Lazy Render 提高首屏体验
- Critical CSS 提前内联
9. 使用 CDN 加速
- 静态资源分发到最近节点
- 减少回源次数、提高命中率
- 自定义缓存配置策略
10. Service Worker 与离线缓存
- 用于缓存页面资源与接口数据
- 提高重复访问性能
- 提供离线能力(PWA)
11. 性能指标与监控
- TTFB(首字节时间)
- FCP、LCP、FID(核心 Web Vitals)
- Resource Timing API、Navigation Timing API
- 使用 Lighthouse、WebPageTest、Chrome DevTools 分析
面试常见问题示例
| 面试题方向 | 具体示例问题 |
|---|---|
| 网络优化策略 | 页面加载慢,网络层如何优化? |
| 协议选择 | HTTP/2 带来哪些性能提升? |
| 缓存优化 | 强缓存和协商缓存的优先级? |
| 压缩优化 | Brotli 与 Gzip 有哪些不同? |
| 请求优化 | 怎么减少第三方资源带来的性能影响? |
| 首屏优化 | 如何优化首屏加载时间?SSR 有哪些作用? |
关联面试题
想要实现页面加载速度提升(性能优化),可以从哪些方向来尝试?
从输入URL到页面加载全过程(6个步骤)
1.DNS 域名解析
2.建立连接(TCP/UDP)
3.发送 HTTP 请求
4.响应 HTTP 请求(这之前服务器一般要处理请求 )
5.页面渲染
6.关闭连接
URL 解析
- 浏览器首先会对输入的 URL 进行解析,将其分解为(5个部分)协议(如 HTTP、HTTPS)、域名(如www.example.com)、端口号(若未指定则使用默认端口,如 HTTP 默认 80 端口,HTTPS 默认 443 端口)、路径(如 /index.html)、查询参数(如?param1=value1¶m2=value2)等部分。
1.DNS 域名解析
- 浏览器缓存查询
- 操作系统缓存查询
- hosts 文件查询
- 本地 DNS 服务器(ISP 提供)查询
- 根域名服务器(.
.)返回顶级域名服务器地址 - 顶级域名服务器返回权威域名服务器地址
- 权威域名服务器返回目标域名对应 IP
- 本地 DNS 服务器将结果缓存并返回
递归查询 与 迭代查询:
- 递归查询:客户端向本地 DNS 请求,期望拿到最终 IP,其他查询步骤由 DNS 服务器完成。
- 迭代查询:DNS 服务器自己一步步查找其他服务器来获取结果。
2.建立TCP连接
- 获得服务器 IP 地址后,浏览器会根据协议与服务器建立连接。对于 HTTP/1.x 和 HTTP/2 协议,通常使用 TCP 连接;对于 HTTP/3 协议,则使用 UDP 连接(基于 QUIC 协议)。
- 在建立 TCP 连接时,会通过三次握手来确保连接的可靠性。客户端发送一个 SYN 包,服务器收到后回复一个 SYN-ACK 包,客户端再发送一个 ACK 包,至此连接建立成功。
3.发送 HTTP 请求
- 连接建立后,浏览器会构建 HTTP 请求消息,并将其发送到服务器。请求消息包括请求行(包含请求方法,如 GET、POST 等,以及请求的 URL 和 HTTP 版本)、请求头(包含各种字段,如 User - Agent、Accept、Cookie 等,用于传递客户端的信息和请求相关的参数)和请求体(如果是 POST 请求,会包含提交的数据)。
4.响应 HTTP 请求
- 浏览器接收服务器返回的 HTTP 响应消息。响应消息包括状态行(包含 HTTP 版本、状态码、状态描述,如 200 OK、404 Not Found 等)、响应头(包含服务器信息、内容类型、缓存控制等字段)和响应体(包含请求的资源内容,如 HTML、CSS、JavaScript 文件,或者图片、视频等二进制数据)。
5.页面渲染
- 浏览器根据响应体中的内容进行页面渲染。如果响应内容是 HTML,浏览器会首先解析 HTML 文件,构建 DOM(文档对象模型)树。在解析过程中,遇到 CSS 样式表和 JavaScript 脚本等资源,会同时发起请求去获取这些资源。
- 浏览器解析 CSS 样式表,构建 CSSOM(CSS 对象模型)树,然后将 DOM 树和 CSSOM 树合并成渲染树(Render Tree)。渲染树只包含需要显示的元素及其样式信息。
- 浏览器根据渲染树进行布局(Layout),计算出每个元素在页面中的位置和大小。然后进行绘制(Paint),将元素的样式绘制到屏幕上,最终呈现出用户看到的页面。
6.连接关闭
- 页面加载完成后,根据不同的情况,连接可能会被关闭或者保持一段时间以便后续的请求复用。对于 HTTP/1.x,如果设置了
Connection: keep - alive,连接会在一定时间内保持打开,以便浏览器可以继续请求其他资源;如果没有设置或者超时时间到了,连接会被关闭。对于 HTTP/2 和 HTTP/3,连接通常会被更有效地复用,以提高性能。
关键事件与性能指标
| 事件 | 触发时机 | 优化意义 |
|---|---|---|
DOMContentLoaded | HTML 和同步 JS 解析完成 | 可尽早执行交互逻辑 |
load | 所有资源(图片、样式表)加载完成 | 标记页面完全加载 |
First Paint (FP) | 首次渲染(背景色、边框等) | 用户感知加载开始 |
First Contentful Paint (FCP) | 首次文本或图像内容渲染 | 核心内容可见性 |
Largest Contentful Paint (LCP) | 最大内容元素渲染完成 | 衡量加载性能的关键指标 |
Time to Interactive (TTI) | 页面可交互(事件监听已绑定) | 用户体验流畅度 |
优化策略
-
网络层优化:
- 启用 HTTP/2 或 HTTP/3,使用 CDN 加速静态资源。
- 资源压缩(Brotli/Gzip)、图片懒加载、域名分片(HTTP/1.1)。
-
渲染层优化:
- 减少重排(Reflow)与重绘(Repaint),使用
requestAnimationFrame。 - 异步加载非关键 CSS/JS,延迟加载第三方脚本。
- 减少重排(Reflow)与重绘(Repaint),使用
-
缓存策略:
- 静态资源设置长期强缓存(
max-age=31536000),动态内容使用协商缓存。
- 静态资源设置长期强缓存(
-
预加载技术:
- 使用
preload、prefetch、preconnect提前获取关键资源。
- 使用
总结
从 URL 输入到页面展示的完整链路涉及 网络协议栈、浏览器引擎、渲染管线 的协同工作。理解各环节的阻塞点和优化手段(如减少 DNS 查询、压缩资源、避免渲染阻塞)是提升 Web 性能的关键。通过 Chrome DevTools 的 Performance 面板可深入分析各阶段耗时,针对性优化关键路径。
浏览器渲染过程中的网络层面常见考点
浏览器渲染过程中,网络层面的考察重点主要集中在从用户输入 URL 到页面渲染完成之间的网络通信过程。这个环节涉及多个关键阶段,是前端性能优化、资源加载、安全和协议理解的核心。
一、从输入 URL 到页面渲染的网络流程(宏观流程)
-
DNS 解析
- 浏览器如何查找域名的 IP?
- 是否存在 DNS 缓存?本地 DNS / 操作系统 / 浏览器级缓存?
- 如何减少 DNS 请求?
-
TCP 连接建立
- 三次握手的过程
- 建立连接的时机
- TCP 连接重用(如 HTTP/1.1 的 Keep-Alive)
-
TLS/SSL 握手(HTTPS)
- HTTPS 建立过程(涉及证书验证、对称加密密钥协商)
- 为什么 HTTPS 比 HTTP 慢?
- TLS 握手和性能优化(如 TLS 1.3 减少 RTT)
-
HTTP 请求发送
- 请求方法(GET/POST)和状态码
- 请求头部(如 Cookie、User-Agent、Accept-Encoding 等)
- 请求体的构造
-
服务器响应
- 响应码(200、304、404、500…)
- 响应头(Content-Type、Cache-Control、Set-Cookie…)
- 响应体(HTML、JS、CSS、图片等)
-
内容传输
- 是否启用了压缩(如 gzip/br)
- 分块传输(Transfer-Encoding: chunked)
- Range 请求、断点续传
-
连接关闭或复用
- HTTP1.1 中的 Keep-Alive
- HTTP/2 的多路复用(连接复用机制)
二、关键协议层考察点
1. DNS 相关
- DNS 解析过程、递归查询、权威解析器
DNS Prefetch、Preconnect优化手段- 使用 CDN 时的 DNS 解析流程
2. HTTP 协议细节
- HTTP1.0 vs HTTP1.1 vs HTTP2 vs HTTP3
- 请求/响应头详解
- 连接管理、流水线机制、队头阻塞(HTTP1.1)问题
- HTTP 缓存机制(协商缓存 & 强缓存)
3. HTTPS 及 TLS
- TLS 1.2 / 1.3 的握手流程
- CA 证书信任体系
- HSTS、OCSP Stapling、安全配置
三、网络性能优化相关考点
- 如何减少网络请求?
- 如何优化 DNS 查询?
- 如何利用缓存减少加载时间?
- TCP/TLS 握手成本如何优化?
- 使用 CDN 的原理和优势
- 静态资源压缩与合并(如 JS/CSS/images)
- 资源预加载策略:
<link rel="preload">、prefetch、dns-prefetch等
四、资源加载相关
- 浏览器加载静态资源的顺序?
- JS/CSS 加载是否阻塞渲染?
defer和async的区别- 图片懒加载、字体加载策略
- Service Worker 的作用与资源拦截能力
五、安全相关
- Mixed Content(HTTPS 页面加载 HTTP 资源)问题
- HSTS 强制使用 HTTPS
- CORS 跨域通信过程
- CSP(内容安全策略)防止 XSS 注入
六、面试常见问题
- 浏览器从输入 URL 到页面显示,网络阶段都做了什么?
- TCP 三次握手、四次挥手过程?
- HTTPS 是如何建立安全连接的?
- HTTP/2 如何实现多路复用?
- 如何通过缓存优化首屏加载时间?
- DNS 查询过程是怎样的?如何优化?
- HTTP 状态码中,301、302、304 各代表什么?
- 如何避免 DNS 重复解析?
- 浏览器对静态资源请求做了哪些优化?
- 如何配置服务器响应头以实现资源缓存策略?
| 模块 | 关注点 |
|---|---|
| DNS | 查询过程、缓存策略、CDN 影响 |
| TCP/TLS | 握手流程、连接复用、性能影响 |
| HTTP 协议 | 各版本特性、缓存机制、状态码 |
| HTTPS 安全 | 证书验证、加密机制、防中间人攻击 |
| 资源加载与性能 | 压缩、缓存、连接优化、加载顺序、预加载策略 |
| 安全与跨域 | CORS、HSTS、CSP、Cookie 安全属性等 |
关联面试题
HTTP/2 如何实现多路复用
HTTP/2 基于单个 TCP 连接,通过 二进制帧 + 流 的核心机制实现多路复用,核心逻辑 3 点:
- 数据拆分为二进制帧摒弃 HTTP/1.1 的文本格式,将请求 / 响应的所有数据拆成小块 二进制帧,每个帧都标记所属的 流 ID。
- 流的并行传输与独立标识每个请求 / 响应对应一个独立的 流,拥有唯一
流ID。同一 TCP 连接上,多个流的帧可以乱序传输,互不干扰。 - 接收端重组服务端 / 客户端根据帧的
流ID识别归属,将乱序的帧重新组装成完整的请求或响应,实现多个请求并行处理。
简单说:一个 TCP 连接,多个流并行传输帧,解决了 HTTP/1.1 连接数限制和队头阻塞问题。
如何通过缓存优化首屏加载时间?
核心是最大化复用缓存资源,减少首屏请求数量和体积,简单说 4 点:
- 强缓存静态资源给 JS/CSS/ 图片等配置
Cache-Control: public, max-age=31536000长期缓存,配合内容哈希命名(如app.abc123.js),内容不变则缓存永久有效,首屏直接读本地缓存。 - 预缓存核心资源用
link rel="preload"预加载首屏关键资源(如核心 JS、字体),用link rel="preconnect"提前建立 CDN 连接,减少 DNS/TCP 握手耗时。 - 协商缓存 HTML首屏 HTML 设
Cache-Control: no-cache+ETag,每次请求先验证是否更新,未更新则返回 304,避免重复下载完整 HTML。 - 利用 Service Worker 缓存离线缓存首屏核心资源(HTML/JS/CSS),二次访问直接从缓存读取,彻底跳过网络请求。
如何避免 DNS 重复解析
核心是减少 DNS 解析次数、复用已有解析结果,简单说 3 种常用方法:
-
利用浏览器 DNS 缓存:浏览器会缓存域名解析结果(默认几十秒到几分钟),尽量让静态资源(JS/CSS/ 图片)部署在同一域名(或同一主域) ,避免频繁解析不同域名。
-
预解析 DNS 连接:在 HTML 头部添加
preconnect或dns-prefetch,提前解析后续要用到的域名,避免后续请求阻塞等待 DNS 解析:<!-- 预建立连接(推荐,不仅解析DNS,还建立TCP/SSL握手) --> <link rel="preconnect" href="https://cdn.example.com"> <!-- 仅预解析DNS(兼容低版本浏览器) --> <link rel="dns-prefetch" href="https://cdn.example.com"> -
使用 CDN 统一域名:将所有静态资源部署到同一个 CDN 域名下,或使用通配符域名,减少不同域名的解析开销;同时避免不必要的跨域域名请求。
浏览器对静态资源请求做了哪些优化
浏览器内置多种优化策略,核心围绕减少请求、提升并行、复用资源,主要有这几点:
-
请求优化
- 「并行请求」:HTTP/1.1 支持同一域名下同时发起多个并行请求(默认 6 个左右),避免单个请求阻塞所有资源;HTTP/2 则通过多路复用实现更高效率的并行。
- 「请求合并」:自动合并部分同源小资源请求(也可通过前端打包工具辅助合并,如 Webpack 打包 JS/CSS)。
- 「请求优先级」:优先加载首屏关键资源(如 HTML、核心 JS/CSS),延后加载非首屏资源(如图片、异步组件)。
-
缓存优化
- 「多级缓存」:依次读取内存缓存 → 磁盘缓存 → 网络请求,复用已缓存的静态资源,避免重复下载。
- 「DNS 缓存」:缓存域名解析结果,减少重复 DNS 查询开销。
- 「协商缓存复用」:缓存未过期时,通过
ETag/Last-Modified验证资源,返回 304 不传输完整资源。
-
其他优化
- 「资源预加载 / 预渲染」:支持
preload(预加载关键资源)、prefetch(预加载后续页面资源)。 - 「自动压缩解压」:自动识别并解压 gzip/Brotli 压缩的资源,减少传输体积。
- 「避免无效请求」:缓存 404/500 等错误响应(短时间),避免重复请求不存在的资源。
- 「资源预加载 / 预渲染」:支持
如何配置服务器响应头以实现资源缓存策略
以 Nginx 为例(最常用),核心是通过 add_header 配置缓存相关响应头,区分「静态资源强缓存」和「核心文件协商缓存」,配置如下:
-
核心配置原则
- 静态资源(JS/CSS/ 图片 / 字体):配置「强缓存」,减少网络请求;
- 核心文件(HTML / 动态接口):配置「协商缓存」,保证资源新鲜度。
-
具体 Nginx 配置代码
server { listen 80; server_name example.com; root /usr/share/nginx/html; # 项目部署目录 # 1. 静态资源:强缓存(1年有效期,长期复用) location ~* .(js|css|png|jpg|jpeg|gif|ico|woff|woff2)$ { # 强缓存核心响应头(优先级最高) add_header Cache-Control "public, max-age=31536000, immutable"; # 兼容 HTTP 1.0,配合 Cache-Control expires 1y; # 开启 gzip 压缩,减小传输体积 gzip on; } # 2. HTML 文件:协商缓存(每次验证资源是否更新) location / { try_files $uri $uri/ /index.html; # SPA 项目路由兼容 # 协商缓存核心响应头(强制校验,不直接缓存文件) add_header Cache-Control "no-cache, must-revalidate"; # 开启 ETag(资源唯一标识,Nginx 默认开启,手动指定更稳妥) etag on; # 开启 Last-Modified(资源最后修改时间) if_modified_since on; # 禁止浏览器直接缓存 HTML,强制走协商流程 expires -1; } } -
关键配置说明
Cache-Control: public, max-age=31536000:允许 CDN / 浏览器缓存,有效期 1 年,静态资源优先使用。immutable:告知浏览器缓存期内资源不会变更,无需发起协商请求,进一步优化性能。no-cache:不是不缓存,而是缓存后每次请求必须和服务器验证资源新鲜度,适合 HTML 等需要实时更新的文件。etag/if_modified_since:协商缓存的核心,服务器通过对比标识判断资源是否更新,未更新返回 304,节省带宽。
补充
如果使用 Apache 服务器,可通过 .htaccess 文件配置响应头,核心缓存策略与 Nginx 一致,仅语法略有差异,例如:
# 静态资源强缓存
<FilesMatch ".(js|css|png|jpg)$">
Header set Cache-Control "public, max-age=31536000"
</FilesMatch>
# HTML 协商缓存
<FilesMatch ".html$">
Header set Cache-Control "no-cache, must-revalidate"
</FilesMatch>
Vue2 项目首屏缓存优化具体配置代码
以下配置覆盖静态资源强缓存、HTML 协商缓存、预加载、打包优化四大核心,直接复用即可。
一、第一步:Webpack 配置(内容哈希命名,支持长期缓存)
Vue2 项目通常基于 webpack 构建(vue-cli 2/3+),核心是给打包后的静态资源加内容哈希,确保内容不变则 URL 不变,缓存长期有效。
1. vue-cli 3+(vue.config.js)
// vue.config.js
module.exports = {
// 1. 配置打包输出文件名,添加内容哈希(chunkhash)
configureWebpack: {
output: {
// 入口文件哈希
filename: 'js/[name].[contenthash:8].js',
// 非入口chunk(如异步组件)哈希
chunkFilename: 'js/[name].[contenthash:8].chunk.js'
}
},
// 2. 配置css打包哈希
css: {
extract: {
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[name].[contenthash:8].chunk.css'
}
},
// 3. 生产环境关闭sourceMap(减小文件体积,提升加载速度)
productionSourceMap: false
}
2. vue-cli 2(build/webpack.prod.conf.js)
// build/webpack.prod.conf.js
module.exports = {
output: {
filename: utils.assetsPath('js/[name].[contenthash:8].js'),
chunkFilename: utils.assetsPath('js/[name].[contenthash:8].chunk.js')
},
// 其他配置同vue-cli 3+,重点修改filename添加contenthash
}
二、第二步:Nginx 配置(缓存策略,强缓存 + 协商缓存)
前端打包后部署在 Nginx 上,通过 Nginx 配置 HTTP 响应头,实现静态资源强缓存、HTML 协商缓存。
# nginx.conf 或 站点配置文件
server {
listen 80;
server_name your-domain.com;
root /usr/share/nginx/html; # 你的Vue打包后dist目录路径
# 1. 静态资源(JS/CSS/图片/字体等):强缓存 1 年
location ~* .(js|css|png|jpg|jpeg|gif|ico|woff|woff2|ttf|eot)$ {
# 强缓存配置,优先级最高
add_header Cache-Control "public, max-age=31536000, immutable";
# 兼容HTTP 1.0,配合Cache-Control
expires 1y;
# 开启gzip压缩,减小传输体积
gzip on;
# 缓存命中日志(可选,便于排查)
access_log /var/log/nginx/cache_access.log;
}
# 2. 首屏 HTML:协商缓存,不直接缓存文件,每次验证新鲜度
location / {
try_files $uri $uri/ /index.html; # Vue SPA 路由兼容
# 协商缓存配置:强制验证资源是否更新
add_header Cache-Control "no-cache, must-revalidate";
# 配置ETag(Nginx默认开启,可手动指定)
etag on;
# 配置Last-Modified
if_modified_since on;
expires -1; # 禁止浏览器直接缓存HTML
}
}
配置说明:
immutable:告诉浏览器该资源在缓存期内不会变更,无需发起协商请求,进一步优化首屏。no-cache:不是不缓存,而是缓存后每次请求都要和服务端验证(协商缓存),保证 HTML 始终是最新的。
三、第三步:Vue 项目内配置(预加载核心资源,提升首屏加载速度)
在 public/index.html 中添加 preload/preconnect,预加载首屏关键资源,减少请求延迟。
<!-- public/index.html -->
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<!-- 1. 预连接CDN(如果静态资源部署在CDN,提前建立连接) -->
<link rel="preconnect" href="https://your-cdn-domain.com">
<!-- 2. 预加载首屏核心CSS(打包后的核心样式文件,替换为你的哈希文件名) -->
<link rel="preload" href="/css/app.abc12345.css" as="style">
<!-- 3. 预加载首屏核心JS(打包后的入口JS,替换为你的哈希文件名) -->
<link rel="preload" href="/js/app.abc12345.js" as="script">
<!-- 4. 预加载关键字体(如有首屏展示的自定义字体) -->
<link rel="preload" href="/fonts/iconfont.woff2" as="font" type="font/woff2" crossorigin>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
说明:
preload仅加载首屏必需资源,不要滥用(过多预加载会占用带宽,适得其反)。- 打包后的资源文件名可在
dist目录中查看,部署时确保路径对应。
四、第四步:可选配置(Service Worker 离线缓存,二次访问极致优化)
Vue2 可通过 workbox-webpack-plugin 实现 Service Worker 缓存,二次访问首屏直接从本地缓存读取,无需网络请求。
1. 安装依赖
npm install workbox-webpack-plugin --save-dev
2. 修改 vue.config.js
// vue.config.js
const { InjectManifest } = require('workbox-webpack-plugin');
module.exports = {
configureWebpack: {
// 其他配置...
plugins: [
// 注入Service Worker配置
new InjectManifest({
swSrc: './src/service-worker.js', // 自定义SW文件
swDest: 'service-worker.js', // 输出文件名
exclude: [/.map$/, /manifest.json$/, /.htaccess$/], // 排除无需缓存的文件
})
]
},
pwa: {
enabled: true, // 开启PWA支持
registerServiceWorker: true, // 自动注册SW
}
}
3. 创建 src/service-worker.js
// src/service-worker.js
workbox.core.setCacheNameDetails({ prefix: 'vue2-app' });
// 缓存首屏核心资源(HTML/JS/CSS)
workbox.routing.registerRoute(
({ request }) => request.destination === 'document' ||
request.destination === 'script' ||
request.destination === 'style',
new workbox.strategies.CacheFirst({
cacheName: 'vue2-app-core',
plugins: [
new workbox.expiration.ExpirationPlugin({ maxAgeSeconds: 31536000 })
]
})
);
// 缓存图片资源
workbox.routing.registerRoute(
({ request }) => request.destination === 'image',
new workbox.strategies.CacheFirst({
cacheName: 'vue2-app-images',
plugins: [
new workbox.expiration.ExpirationPlugin({ maxEntries: 100, maxAgeSeconds: 86400 })
]
})
);
五、配置验证
-
打包项目:
npm run build,查看dist目录,确认资源文件名是否带有 8 位哈希。 -
部署到 Nginx 后,打开浏览器开发者工具(F12)→ Network 面板,刷新页面:
- JS/CSS 等静态资源:Status 为
200 (from disk cache)或200 (from memory cache),表示强缓存生效。 - index.html:Status 为
200或304,表示协商缓存生效。
- JS/CSS 等静态资源:Status 为
-
二次访问:首屏加载时间大幅降低(尤其是 Service Worker 配置后,离线也可访问)。
总结
- 核心是内容哈希 + 长期强缓存,保证静态资源不重复下载。
- HTML 用协商缓存,保证首屏内容最新。
preload预加载关键资源,进一步缩短首屏等待时间。- Service Worker 针对二次访问优化,实现离线可用。
如果部署后出现缓存不生效、资源 404 等问题,可优先检查 Nginx 路径配置和资源哈希文件名是否对应。