为什么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关键字(如function、var)和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.gz和style.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小时,观察服务器负载和用户访问日志,再全量切换。这个优化的性价比,远超大多数前端代码层面的手术。
延伸阅读
