Nginx 开启 Gzip 与 Brotli 压缩实战:网页传输体积立减 70%

Nginx 开启 Gzip 与 Brotli 压缩实战:网页传输体积立减 70%

引言

个人站长的服务器带宽通常都不宽裕,尤其是那些买了入门级 VPS 的朋友,一个月流量就那么几百 GB,一个不小心就被图片和脚本吃光了。而访客端的体验更直接:页面文件越大,加载越慢,跳出率越高。其实有一个被很多人忽略的优化手段,既不用升级服务器,也不用改代码,只要在 Nginx 里动几行配置,就能让 HTML、CSS、JavaScript 这些文本资源的传输体积减少六成到七成——这就是 HTTP 压缩。本文从 Gzip 讲到更先进的 Brotli,把原理、配置、验证和避坑一次说清楚。

一、HTTP 压缩是怎么工作的

HTTP 压缩的原理并不复杂。浏览器在发起请求时,会在请求头里带上 Accept-Encoding 字段,声明自己支持的压缩算法,例如 gzip、deflate、br 等。服务器收到请求后,如果发现资源是适合压缩的文本类型,就用浏览器支持的算法把内容压缩后再传输,同时在响应头里用 Content-Encoding 字段标明用了哪种算法。浏览器收到响应后自动解压渲染,整个过程对用户完全透明。

关键点在于:压缩和解压都是无损的,页面显示效果没有任何变化,省掉的只是网络传输的那部分字节。对于 HTML、CSS、JavaScript、JSON 这类文本资源来说,重复的标签和关键字极多,压缩率非常可观;而图片、视频、音频这类本身就是压缩格式的二进制文件,再压一遍收益极小还浪费 CPU,所以要排除在压缩范围之外。

为什么文本资源的压缩率能这么高?因为 HTML、CSS、JavaScript 这类文件里存在大量重复出现的结构:成对的标签名、重复的属性名、公共的类名和函数名、风格统一的注释,还有为了可读性保留的换行和缩进。压缩算法正是利用这种重复性,用更短的编码去替换高频片段,所以文件越大、重复内容越多,压缩收益就越明显。举个直观的例子:一个流行的前端脚本库,原始体积两百多 KB,Gzip 压缩后往往只剩六七十 KB;一份充满重复标签的 HTML 页面,压缩率甚至能超过七成。反过来看图片和视频,它们内部已经是熵编码后的紧凑数据,几乎找不到可供压缩的重复结构,硬压不仅体积纹丝不动,还会白白消耗服务器的 CPU 资源。

二、Nginx 开启 Gzip 压缩

Gzip 是历史最悠久、兼容性最好的压缩算法,几乎所有 Nginx 发行版都默认编译了 gzip 模块,直接开启即可。在 nginx.conf 的 http 段里加上下面这段配置:

gzip on;
gzip_min_length 1k;
gzip_comp_level 6;
gzip_vary on;
gzip_types text/plain text/css text/xml application/json
           application/javascript application/xml image/svg+xml
           application/xhtml+xml application/rss+xml
           font/ttf font/otf application/vnd.ms-fontobject;

逐行解释一下:gzip on 是总开关;gzip_min_length 1k 表示只有超过 1KB 的响应才压缩,避免压缩小文件时得不偿失;gzip_comp_level 6 是压缩级别,取值范围 1 到 9,级别越高压缩率越高但越耗 CPU,6 是官方推荐的性价比平衡点;gzip_vary on 会让 Nginx 在响应头里加上 Vary: Accept-Encoding,方便中间缓存节点正确处理;最关键的是 gzip_types,它列出了需要压缩的 MIME 类型,text/html 是默认压缩的不用写,但 CSS、JavaScript、JSON、SVG 这些必须手动声明,否则不生效。这里有个很多新手踩过的坑:以为开了 gzip on 就万事大吉,结果 CSS 和 JS 根本没被压缩,就是因为没写 gzip_types。

改完配置执行 nginx -t 检查语法,然后 nginx -s reload 平滑重载,配置就生效了。注意不要用 restart,reload 不会中断现有连接,对线上站点更友好。

三、Brotli 比 Gzip 强在哪

Brotli 是 Google 在 2015 年开源的压缩算法,专门为 Web 内容优化过。它的压缩率比 Gzip 再高 15% 到 20%,同时解压速度也很快,不会给访客的设备带来明显负担。经过这些年的普及,主流浏览器对 Brotli 的支持已经非常完善,Chrome、Edge、Firefox、Safari 的现代版本都支持 br 编码,站长完全不用担心兼容性问题——配置得当的情况下,老浏览器会自动退回 Gzip,两边都不耽误。

用一组典型数据感受一下差距:一篇 30KB 左右的 HTML 页面,Gzip 压缩后大约 7KB 到 8KB,Brotli 能压到 6KB 左右;一个 100KB 的 CSS 文件,Gzip 后约 15KB,Brotli 后约 12KB。看起来百分比差距不大,但流量是日积月累的,对于流量有限的草根站长来说,每一分带宽都值得省。

四、给 Nginx 装上 Brotli 模块

和 Gzip 不同,官方 Nginx 默认并不带 Brotli 模块,需要自己编译加载。先用 nginx -V 查看当前 Nginx 的版本和编译参数,记下 configure arguments。然后下载同版本的 Nginx 源码和 ngx_brotli 模块源码,用动态模块的方式编译,这样不影响现有的 Nginx 安装:

git clone https://github.com/google/ngx_brotli.git
cd nginx-版本号
./configure --with-compat --add-dynamic-module=../ngx_brotli
make modules
cp objs/ngx_http_brotli_filter_module.so /usr/lib/nginx/modules/
cp objs/ngx_http_brotli_static_module.so /usr/lib/nginx/modules/

然后在 nginx.conf 的顶层加上 load_module 指令加载这两个模块,再执行 nginx -t 验证,最后 reload 生效:

load_module modules/ngx_http_brotli_filter_module.so;
load_module modules/ngx_http_brotli_static_module.so;

如果你用的是 OpenResty 或者某些第三方发行版,可能已经内置了 Brotli 模块,直接用 nginx -V 的输出确认一下即可,省去编译的麻烦。

五、生产环境完整配置示例

Brotli 和 Gzip 可以同时开启、互不冲突:客户端声明支持 br 时,Nginx 优先返回 Brotli 压缩的内容;客户端不支持时自动回落到 Gzip。把两套配置合并在一起,就得到了生产环境可用的完整配置:

gzip on;
gzip_min_length 1k;
gzip_comp_level 6;
gzip_vary on;
gzip_types text/plain text/css application/json application/javascript
           image/svg+xml application/xml font/ttf font/otf;

brotli on;
brotli_min_length 1k;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/javascript
             image/svg+xml application/xml font/ttf font/otf;

如果服务器的 CPU 比较紧张,还可以考虑静态预压缩方案:用 gzip_static 和 brotli_static 指令配合,提前用命令行工具把文件压好一份 .gz 和 .br 版本放在磁盘上,Nginx 直接发送预压缩文件,完全不在请求时占用 CPU。这个方案特别适合静态资源多、流量波动大的站点,代价只是多占一点磁盘空间。

使用静态预压缩时,需要先把文件压好并放在同级目录,例如 style.css 旁边放置 style.css.gz 和 style.css.br,Nginx 收到带 Accept-Encoding 请求头的访问后会优先查找对应的预压缩文件并直接发送,找不到时才回退到实时压缩。预压缩还有一个隐藏优势:因为压缩只发生在部署那一刻,完全可以用最高级别去压,比如 Gzip 用 9 级、Brotli 用 11 级,把体积压到极限也不心疼 CPU,反正请求时只是发文件而已。如果你的静态资源是通过脚本批量生成的,完全可以把压缩步骤写进构建流程,实现发布即压缩的自动化。

六、验证压缩是否生效

配置完成后如何确认真的生效了?最简单的办法是用 curl 模拟浏览器的请求头:

curl -sI -H "Accept-Encoding: gzip, deflate, br" https://www.zz1984.com/ | grep -i content-encoding

如果响应里出现 Content-Encoding: br,说明 Brotli 生效了;出现 Content-Encoding: gzip 则说明走了 Gzip。也可以用 curl -s -H "Accept-Encoding: br" 对比输出内容的大小,或者直接在浏览器开发者工具的 Network 面板里,对比资源大小和传输大小两个数字,传输大小明显小于资源大小就说明压缩生效了。注意测试时要带上 Accept-Encoding 请求头,否则服务器不知道你支持压缩,返回的就是未压缩的原始内容。

七、避坑清单

压缩配置看起来简单,实际使用中有几个坑值得留意:

  • 压缩级别不要盲目调高:Brotli 的级别范围是 1 到 11,超过 6 之后压缩率提升非常有限,CPU 消耗却成倍增长,高并发下可能拖慢服务器,6 级是大多数场景的最优解;
  • 小文件不要压:几百字节的响应压缩后可能比原来还大,gzip_min_length 和 brotli_min_length 就是为这个准备的;
  • 图片视频音频千万别压:JPEG、PNG、WebP、MP4 本身就是压缩格式,强行加入 gzip_types 只会白白消耗 CPU,没有任何体积收益;
  • 注意 CDN 的双重压缩问题:如果网站套了 CDN,源站开启压缩后,要确认 CDN 节点支持 Brotli 直通,否则可能出现 CDN 解压再压缩的重复劳动,甚至导致部分老浏览器拿到无法识别的内容;
  • 压缩和缓存是两回事,别混为一谈:压缩解决的是传输体积,缓存解决的是重复请求。对于 CSS、JS 这类不常变化的资源,建议同时在响应头里设置较长的 Cache-Control 有效期,让访客二次访问直接命中本地缓存,连请求都不再发出,压缩加上缓存才是性能优化的完整闭环;
  • 修改配置后一定先 nginx -t 再 reload,语法错误会导致整个 Nginx 无法重载,线上站点直接受影响。

八、结语

开启 HTTP 压缩是性价比最高的网站加速手段之一:零代码改动、零硬件投入,只需要几分钟的配置时间,就能让页面传输体积大幅下降,尤其对带宽有限、访客网络环境复杂的草根站长站点来说收益明显。建议优先把 Gzip 开起来,条件允许的话再编译 Brotli 模块,让两种算法各司其职。配置完成后记得用 curl 和浏览器开发者工具双重验证,确认 CSS、JS、HTML 都真正被压缩了,再对比一下压缩前后的加载耗时,你会看到立竿见影的变化。

Last modification:September 10th, 2026 at 07:59 am

Leave a Comment