问题背景:大数据量传输导致的性能瓶颈
在现代Web应用开发中,我们经常会遇到需要从后端获取大量数据的场景。当后端返回的数据量非常大(达到MB级别)时,传统的传输方式会导致严重的性能问题。
从第一张网络请求时序图可以看到:
- 请求排队时间(Queued at)为2.55秒
- 实际开始时间(Started at)为3.06秒
- 整个传输过程耗时长达1分钟
- 其中内容下载(Content Download)阶段占用了大部分时间
这种性能问题直接导致了用户体验下降,还引发请求超时等严重问题。
解决方案:Gzip压缩传输
针对这一问题,我们采用了Gzip压缩技术方案,通过前后端协作,实现了数据传输效率的显著提升。
后端改造
后端进行了以下优化:
- 对大数据响应进行Gzip压缩处理
- 将压缩后的数据存入缓存
- 通过CDC(变更数据捕获)监听数据库变更
- 定时同步更新缓存数据
前端改造
前端在响应拦截器中添加了Gzip解压处理:
if (response?.headers?.["d-content-encoding"] === "gzip" && res.data) {
res.data = unZip(res?.data);
}
解压工具函数实现:
import pako from 'pako';
export const unZip = (data: string | ArrayBuffer) => {
try {
let compressedData;
// 检查data是否存在且为字符串
if (typeof data === 'string') {
// 检查是否是base64格式(简单检查)
const base64Pattern = /^[A-Za-z0-9+/]*={0,2}$/;
if (base64Pattern.test(data)) {
// 是base64编码的gzip数据
compressedData = Uint8Array.from(atob(data), (c) => c.charCodeAt(0));
} else {
// 可能是直接的gzip二进制字符串
compressedData = new Uint8Array(data.split('').map((c) => c.charCodeAt(0)));
}
} else if (data instanceof ArrayBuffer) {
compressedData = new Uint8Array(data);
} else if (data instanceof Uint8Array) {
compressedData = data;
} else {
console.log('gzip errror');
return null;
}
// 使用pako解压缩
const decompressed = pako.ungzip(compressedData, { to: 'string' });
const decompressedData = JSON.parse(decompressed);
return decompressedData;
} catch (error) {
console.log('gzip errror');
return null;
}
};
优化效果对比
实施Gzip压缩方案后,我们从第二张网络请求时序图可以看到显著改善:
- 请求排队时间(Queued at)缩短至1.6分钟
- 实际开始时间(Started at)同样为1.6分钟
- 整个传输过程耗时仅约2.25秒
- 内容下载(Content Download)时间大幅减少
技术方案优势
- 传输效率提升:数据量减少数十倍,传输时间从分钟级降至秒级
- 带宽节省:减少网络流量消耗
- 缓存友好:压缩后的数据更小,缓存效率更高
适用场景
这种技术方案特别适用于以下场景:
- 需要一次性返回大量数据给前端
- 数据主要为文本格式(JSON、XML等)
- 数据变化频率不高,适合缓存
- 网络条件受限的环境(如移动网络)
结论
通过引入Gzip压缩传输方案,我们成功解决了大数据量传输导致的性能瓶颈问题。从实际效果来看,传输效率提升了几十倍,显著改善了用户体验。这种方案实现相对简单,但效果显著。