Gzip压缩实战:提升网站加载速度的关键技术

UX-敏涵 工具 阅读 1,300
赞 30 收藏
二维码
手机扫码查看
反馈

项目初期的技术选型

上个月接了个老项目重构,前端资源包体积大得离谱——首屏 JS 超过 1.8MB,CSS 近 500KB。用户反馈加载慢,尤其在弱网环境下基本要等 5 秒以上。团队内部讨论后,决定先从最直接的方案入手:Gzip 压缩。

Gzip压缩实战:提升网站加载速度的关键技术

其实 Gzip 这东西早该上了,但之前运维说“Nginx 默认开了”,结果查了才发现根本没生效。这次我亲自下场搞,毕竟资源体积压不下来,后面做懒加载、代码分割都白搭。

配置完发现没生效?别急,先看响应头

我一开始以为只要在 Nginx 里加几行配置就行,结果部署完用 DevTools 一查,Content-Encoding: gzip 根本没出现。折腾了半天,发现两个坑:

  • 静态资源被 CDN 缓存了,新配置没刷新
  • Nginx 的 gzip_types 没包含 text/cssapplication/javascript(默认只压缩 text/html)

修正后的 Nginx 配置长这样:

gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
  text/plain
  text/css
  application/json
  application/javascript
  text/xml
  application/xml
  application/xml+rss
  text/javascript;

注意 gzip_min_length 设成 1024 字节,太小的文件压缩反而可能变大,没必要。gzip_comp_level 从 1 到 9,6 是性价比最高的,再高 CPU 开销大,体积减少微乎其微。

最大的坑:动态 API 响应没压缩

静态资源搞定后,发现接口返回的 JSON 数据还是原样。比如一个 /api/user/profile 接口,返回 300KB 的 JSON,没压缩。这时候才意识到:Gzip 不仅对静态文件有效,动态内容也得处理。

我们的后端是 Node.js + Express,于是我加了 compression 中间件:

const compression = require('compression');
const express = require('express');

const app = express();
app.use(compression({
  threshold: 1024, // 小于 1KB 的不压缩
  filter: (req, res) => {
    // 某些特殊路径跳过压缩(比如监控探针)
    if (req.path.includes('/health')) return false;
    return compression.filter(req, res);
  }
}));

这里踩了个小坑:threshold 默认是 1KB,但有些小接口(比如 800 字节)其实压缩后能省 30%,所以我后来调到 512。不过要注意,太小的响应压缩收益低,还增加 CPU 负担,得权衡。

测试时用 curl -H "Accept-Encoding: gzip" https://jztheme.com/api/data 看响应头和 body,确认 Content-Encoding: gzip 出现,并且数据确实是压缩过的(乱码就对了)。

浏览器兼容性?其实不用太担心

本来我还担心老旧浏览器不支持 Gzip,查了下 CanIUse,连 IE6 都支持。现代浏览器更不用说,只要请求头带 Accept-Encoding: gzip,服务器就会返回压缩内容,浏览器自动解压。所以这块基本零成本,放心开。

效果评估:体积砍半,但首屏时间没降那么多

上线后看数据:

  • JS 从 1.8MB → 580KB(压缩率 68%)
  • CSS 从 490KB → 120KB(压缩率 75%)
  • API JSON 平均从 250KB → 80KB

看起来很爽,但实际首屏时间只从 5.2s 降到 3.8s。为什么?因为还有 DNS、TCP、TLS、服务端渲染延迟这些环节。Gzip 只解决传输体积,不解决连接建立开销。

不过在 3G 网络下提升明显,用户反馈“终于不用转圈那么久了”。也算值了。

没完全解决的小问题

有两个细节到现在也没动:

  • 某些第三方 SDK(比如埋点脚本)是外链的,没法控制是否压缩。只能祈祷对方开了 Gzip(大部分主流 CDN 都开了)
  • 图片资源没走 Gzip,因为本身是二进制,Gzip 压不动。这部分我们后续用 WebP + CDN 自适应做了优化,但那是另一个故事了

其实也可以考虑 Brotli,压缩率比 Gzip 高 15%~20%,但需要 Nginx 1.11.8+,而且构建时预压缩会增加部署复杂度。这次项目时间紧,就没折腾。

回顾与反思

回头看,Gzip 真的是“投入产出比最高”的性能优化手段之一。配置简单,风险低,效果立竿见影。但有几个教训值得记:

  • 别信“默认开启”,一定要用 DevTools 或 curl 验证响应头
  • 静态资源和动态接口要分开处理,前端开发者容易忽略后端那部分
  • 压缩不是万能的,体积小了,但网络 RTT、服务端延迟这些瓶颈还在

另外,本地开发时可以用 webpack 的 compression-webpack-plugin 生成 .gz 文件,配合 Nginx 的 gzip_static on; 直接返回预压缩文件,避免运行时压缩的 CPU 开销。不过我们项目没用,因为容器化部署后 CPU 资源够用,实时压缩更灵活。

核心代码其实就那几行,但排查过程花了我大半天。希望你别重复踩这些坑。

以上是我个人在项目中使用 Gzip 的完整经验,有更优的实现方式欢迎评论区交流。这个技巧的拓展用法还有很多(比如结合 Service Worker 缓存压缩包),后续会继续分享这类博客。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论