全站启用Brotli压缩算法替代Gzip提升Web加载速度实战

Brotli压缩算法相比传统Gzip可再压缩20%-30%,但众多站点仍在观望。本文从算法原理出发,手写Nginx与Apache的配置脚本,附带参数调优、浏览器兼容验证与回滚方案。不堆砌数字,只给可直接落地的命令。

全站启用Brotli压缩算法替代Gzip提升Web加载速度实战
封面图:ZuCDN · ZuCDN 原创

为什么Gzip不再是唯一选择

HTTP压缩在网页优化中属于“低投入高回报”的环节。过去十年,Gzip几乎垄断了文本传输压缩市场,直到Google在2015年开源了Brotli。与Gzip使用Deflate算法不同,Brotli基于LZ77的改进版和一个预定义的静态字典(包含英文、HTML标签、CSS属性等高频片段),对Web资源有天然的匹配优势。

实测数据显示,同样等级6的压缩,Brotli输出的文件体积比Gzip小20%-30%。这意味着在相同的带宽条件下,用户下载CSS、JS、HTML的时间可以缩短近四分之一。对于移动端流量计费的国家或地区,这个优化直接降低了用户的数据消耗。

但许多站长停留在“知道但不敢动”的状态——担心浏览器兼容性,害怕配置错误导致服务异常。本文会逐一拆解这些顾虑。

Brotli的核心优势与适用场景

压缩率对比:相同等级下更小的体积

Gzip的压缩等级范围为1-9,Brotli为0-11。在默认等级(Gzip 6 vs Brotli 6)下,Brotli对HTML的压缩率通常高出15%-25%,对CSS和JS的提升更明显。原因是Brotli内置了静态字典,能识别常见的JavaScript关键字(如functionvar)和CSS属性名,直接引用字典条目而非逐字编码。

压缩速度权衡:不是越快越好

Brotli的高压缩等级(如11)会在服务端消耗更多CPU,尤其在被频繁请求的动态页面上。但静态资源(字体、图片、打包后的JS/CSS)无需实时压缩,可以提前用高等级压缩并缓存。对于动态HTML,推荐使用Brotli等级4-5,压缩比已优于Gzip 6,CPU开销却更低。

浏览器支持现状

所有现代浏览器(Chrome 50+、Firefox 44+、Safari 11+、Edge 15+)均支持Brotli。唯二的“缺口”是:未更新至TLS 1.2以上的老旧浏览器(约占全球流量的0.5%),以及Android系统WebView在5.0以下时不支持。鉴于TLS 1.2已是当前网站标配,仅需在Nginx或Apache配置中为这类客户端回退到Gzip即可。

实战配置:Nginx + Brotli

Nginx原生不包含Brotli模块,需要编译安装或者使用动态模块。这里给出最普适的编译方案,以及预编译模块的引用方法。

步骤一:安装Brotli模块

使用Nginx源码编译是最稳妥的方式,不会产生模块版本冲突。

# 下载Nginx源码与Brotli模块
wget http://nginx.org/download/nginx-1.24.0.tar.gz
wget https://github.com/google/ngx_brotli/archive/master.zip
unzip master.zip
mv ngx_brotli-master ngx_brotli

# 编译时加入模块
./configure --add-module=../ngx_brotli
make && make install

对于已安装Nginx的用户,可通过动态模块加载(需先确认当前Nginx版本是否支持动态模块)。Ubuntu/Debian可使用官方PPA:

sudo apt install nginx-extras

内含预编译好的ngx_brotli模块。

步骤二:启用Brotli压缩

nginx.conf的http块中加入:

brotli on;
brotli_comp_level 6;
brotli_static on;
brotli_types text/plain text/css application/javascript application/json image/svg+xml application/xml text/xml application/wasm;
  • brotli_static on:若存在预压缩的.br文件(如style.css.br),直接返回,避免重复压缩。建议构建工具(如Webpack插件)生成静态资源的.br版本。
  • brotli_comp_level 6:平衡CPU与压缩比,日常动态请求够用。若服务器资源充沛且静态资源占主导,可提升至8。
  • brotli_types:列出需要压缩的MIME类型。WebAssembly (.wasm) 也建议加入,同样受益于Brotli。

步骤三:客户端回退(兼容Gzip)

Nginx可通过map指令判断客户端是否支持Brotli:

map $http_accept_encoding $accept_brotli {
    default 0;
    ~*br 1;
}

server {
    location / {
        if ($accept_brotli = 0) {
            gzip on;
            gzip_vary on;
            gzip_types *;
        }
    }
}

这段配置意味着:如果客户端请求头Accept-Encoding中包含br,则使用Brotli压缩;否则执行Gzip。不需要同时启用两个压缩模块,避免重复压缩。

实战配置:Apache + Brotli

Apache通过mod_brotli模块实现,安装和管理相对简单。

步骤一:启用mod_brotli

sudo a2enmod brotli
sudo systemctl restart apache2

步骤二:配置压缩规则

<IfModule brotli_module>
    AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/css application/javascript application/json
    BrotliCompressionLevel 6
</IfModule>

Apache也可利用AddEncoding x-brotli .br配合RewriteRule实现预压缩文件投放,但更稳妥的做法是直接使用mod_negotiation的MultiViews功能。不过建议部署CDN时在源站保留Gzip作为回退,CDN层负责协商。

验证与回滚

检查压缩是否正确生效

使用curl命令模拟请求,查看响应头Content-Encoding

curl -H "Accept-Encoding: br" -I https://example.com/style.css

返回中应包含Content-Encoding: br。若未出现,检查Nginx日志或Apache的错误日志。

验证浏览器兼容

可以用在线工具(如KeyCDN测试工具)选择不同浏览器版本请求你的页面。若发现某个老旧浏览器加载异常,检查该浏览器是否绕过Brotli直接获取了未压缩的原始文件(这取决于你的回退配置是否正确)。

安全回滚方案

在Nginx中,临时禁用Brotli只需注释掉brotli on;行并重启服务即可。对于Apache,执行sudo a2dismod brotli。但更推荐的做法是保持Brotli模块加载,将brotli_comp_level改为0(等于关闭压缩),同时确保Gzip打开,这样可以零风险切换。

常见陷阱与调优建议

  • CDN场景下的协商问题:许多CDN(Cloudflare、AWS CloudFront)支持Brotli,但源站必须返回Vary: Accept-Encoding头,否则CDN可能缓存错误版本。在Nginx中添加add_header Vary Accept-Encoding;即可。
  • 预压缩文件命名冲突:若同时存在style.css.gzstyle.css.br,Nginx的brotli_static只会查找.br为后缀的文件,不会自动回退到.gz。因此静态资源的构建流程建议统一为Brotli预压缩,Gzip留给动态请求处理。
  • CPU过载预警:在流量暴增时(如促销活动),Brotli高等级压缩可能成为瓶颈。监控指标应关注“压缩并发数”而不是单纯CPU百分比。建议在Nginx中设置brotli_buffers 32 8k;来调整缓冲区大小,减少内存分配开销。
  • WebAssembly的压缩.wasm文件虽然体积较大,但Brotli可以压缩至原大小的30%以下,加载时间缩短非常明显。务必在brotli_types中加入application/wasm

总结

Brotli不是花哨的技术替代,而是对现有基础设施的效率升级。从Nginx的一行模块编译到Apache的一键启用,实际配置代码不超过20行。只要搭配合理的回退策略和CDN Vary头,全站启用Brotli的风险几乎为零。带来的加载速度提升却是用户可感知的——尤其是首屏体积缩小后,3G网络下的白屏时间能减少数百毫秒。

如果你还在运行着仅Gzip的配置,今天就可以按照本文的步骤进行一次替换测试。先在一个测试子域名上运行48小时,观察服务器负载和用户访问日志,再全量切换。这个优化的性价比,远超大多数前端代码层面的手术。

延伸阅读