页面明明很快,打开浏览器却要等上两三秒,很多人第一反应是升级带宽(网络链路在单位时间内可传输的数据量上限)或换更大的服务器,其实真正拖慢首屏的往往是那些没被压缩的 CSS、JavaScript 和 HTML 文件。这篇文章指南教你用 Nginx 自带的 gzip 和更高效的 Brotli(一种由 Google 开发的开放压缩算法,压缩率通常优于 gzip)把传输体积降下来,服务器不用多花钱,页面加载速度却能明显提升。gzip(GNU zip,GNU 项目开发的通用文件压缩工具,也是 HTTP 最广泛支持的压缩方式)几乎人人都会配,但压缩级别、MIME(Multipurpose Internet Mail Extensions,多用途互联网邮件扩展类型,用于标识文件内容类型)范围没选对,效果会打很大折扣。本文从原理讲到验证,帮助你一次性把压缩配置落地到生产环境。

压缩传输的原理与收益
HTTP 压缩的原理并不复杂:服务器在把 HTML、CSS、JS 等文本资源发给浏览器之前,先用压缩算法把文件体积变小,浏览器收到后再自动解压还原。网络传输的字节少了,下载时间自然变短,尤其对移动端弱网环境,收益更明显。
gzip 是 HTTP 生态里兼容性最好的压缩方式,几乎所有浏览器和 CDN(Content Delivery Network,内容分发网络,把内容缓存到离用户更近的节点)都支持。Brotli 是更新的算法,在相同压缩级别下通常能把体积再压掉 10% 到 15%,而且解压速度更快,但需要 Nginx 安装额外的 ngx_brotli 模块。
以一个常见的 jQuery 库为例做个对比说明:原始文件约 300KB 的 JavaScript,gzip 压缩后大约降到 85KB 左右,Brotli 在较高压缩级别下可进一步压到 70KB 上下。这里的数值仅为示例区间,实际效果因文件内容而异——文本越规整、重复内容越多,压缩收益越大,图片、视频这类已经是压缩格式的文件再压意义不大。
# 用 curl 查看某个静态文件当前是否已压缩(关注响应头中的 Content-Encoding) curl -sI https://your-domain.com/app.js | grep -i content-encoding
上面命令的返回如果出现 gzip 或 br,说明该资源已经被压缩;如果空着,说明还没开启压缩,正好是本文要解决的问题。示例中的域名请替换成你自己的站点。
开启 gzip:Nginx 基础配置
Nginx 默认编译就带 gzip 模块,所以开启 gzip 不需要装任何东西,只要在 http 块里打开开关并指定要压缩的文件类型即可。下面是一份生产可用的 gzip 配置,放在 nginx.conf 的 http 段落内:
# 打开 gzip,关闭则设为 off
gzip on;
# 低于 1KB 的响应不压缩,避免浪费 CPU
gzip_min_length 1024;
# 压缩级别 1-9,建议 5,兼顾体积与 CPU
gzip_comp_level 5;
# 指定要压缩的 MIME 类型
gzip_types text/plain text/css application/javascript application/json
image/svg+xml application/xml text/xml text/javascript;
# 是否在响应头加入 Vary: Accept-Encoding,便于 CDN 正确缓存
gzip_vary on;
这份配置里值得留意的有三处。gzip_min_length 1024 是过滤小文件,因为压缩极小的响应反而可能因为额外头部而变大,属于典型的资源浪费。gzip_comp_level 5 是压缩级别,1 最快但压得少,9 压得最狠但很吃 CPU,对绝大多数业务站点 5 或 6 是性价比最高的典型区间。gzip_types 只列文本类类型,图片、PDF、ZIP 等已经压缩过的格式不要放进去,否则白费 CPU。
配置改完记得重载 Nginx 让改动生效:
# 先测试配置语法是否正确,再平滑重载 nginx -t systemctl reload nginx
关于 Nginx 配置的更多坑,比如请求限流对静态资源的影响,可以参考 Nginx 请求限流配置,理解限流规则与压缩同时启用时的配合方式。
升级到 Brotli:模块安装与启用
Brotli 需要 Nginx 加载 ngx_brotli 模块。如果你的 Nginx 是源码编译安装的,最简单的方式是用 --add-dynamic-module 把 ngx_brotli 编成动态模块;如果用发行版自带的 Nginx,则要看系统源里是否提供对应的 brotli 模块包。下面是源码方式的一个编译示意:
# 克隆 ngx_brotli 模块源码(示例路径,按实际版本获取) git clone https://github.com/google/ngx_brotli.git /usr/local/src/ngx_brotli cd /usr/local/src/ngx_brotli && git submodule update --init # 重新编译 Nginx,并追加动态模块参数 ./configure --add-dynamic-module=/usr/local/src/ngx_brotli make && make install
编译安装后,在 Nginx 配置文件顶部用 load_module 加载模块,然后在 http 块里开启 Brotli:
# 加载 Brotli 动态模块(路径随安装位置变化)
load_module modules/ngx_http_brotli_filter_module.so;
load_module modules/ngx_http_brotli_static_module.so;
http {
# 打开 Brotli 压缩
brotli on;
brotli_comp_level 6;
brotli_static on;
brotli_types text/plain text/css application/javascript
application/json image/svg+xml;
}
brotli_static on 可以预先用 brotli -k 生成 .br 静态文件,让 Nginx 直接发送预压缩文件,省去每次请求时的实时压缩开销,适合文件很少变动的场景。需要提醒的是,Brotli 和 gzip 并不冲突,浏览器会优先选择自己支持的更优算法,所以两者可以同时开启,Nginx 会根据请求头里的 Accept-Encoding 自动决定用哪种方式响应。
如果你的服务器还承担数据库工作负载,压缩配置带来的性能收益和数据库优化是两件独立的事,建议一并处理,可参考 MySQL 慢查询分析与优化 把后端瓶颈也一并排查。
压缩级别、MIME 类型与缓存策略
很多站点压缩效果不佳,问题往往出在 MIME 类型列表不全。前端资源不止 css 和 js,还包括 JSON 接口、SVG 图标、XML 数据等,这些都应该放进压缩类型。可以按下面的清单核对:
- HTML:text/html、application/xhtml+xml
- CSS:text/css
- JavaScript:application/javascript、text/javascript
- JSON:application/json
- 图标:image/svg+xml(SVG 是文本,可以压缩)
- XML:text/xml、application/xml
压缩级别方面,gzip 建议 5,Brotli 建议 6 或 7。Brotli 即使级别较低也往往比 gzip 高级别压得更小,所以可以放心使用。此外,压缩应和浏览器缓存配合:只有设置了合适的 Cache-Control 与 ETag,浏览器才会把压缩后的资源复用到下一次访问,否则每次都要重新下载。一个常用做法是对带 hash 的文件名设置长缓存:
# 带版本号的静态资源设置长缓存,文件名变化时自动失效
location ~* \.(?:css|js)$ {
expires 30d;
add_header Cache-Control "public";
}
如果站点还用到 Redis 做页面或数据缓存,压缩与缓存之间也要注意配合,避免缓存了未压缩或重复压缩的内容,相关实践可以参考 Redis 持久化与恢复,理解缓存层与 Web 层各自的分工。
验证与调优:观察实际压缩效果
配置完成不等于效果达到预期,一定要用真实请求验证。先用 curl 模拟浏览器请求,检查响应头里是否出现预期的编码:
# 用 Accept-Encoding: br 请求,确认是否返回 Brotli 压缩 curl -sI -H "Accept-Encoding: br" https://your-domain.com/app.js # 用 gzip 请求,确认 gzip 是否生效 curl -sI -H "Accept-Encoding: gzip" https://your-domain.com/app.js
如果返回头里 Content-Encoding 显示 br 或 gzip,说明压缩已生效。接下来对比压缩前后的大小,看收益是否明显:
# 分别下载未压缩与压缩后的文件,比较体积(示例域名替换为真实站点) curl -s -o /tmp/raw.js https://your-domain.com/app.js curl -s -H "Accept-Encoding: gzip" -o /tmp/gz.js.gz https://your-domain.com/app.js ls -lh /tmp/raw.js /tmp/gz.js.gz
示例中,如果 raw 文件约 200KB 而压缩后约 50KB,说明压缩率在 75% 左右,属于正常的典型区间。如果你还想量化全站收益,可以结合监控面板观察带宽与 TTFB(Time to First Byte,首字节时间,指从发起请求到收到第一个响应字节的耗时)的变化,Grafana 服务器部署实践 提供了一套现成的可视化监控方案,方便你长期跟踪优化效果。

避坑要点
压缩配置看着简单,踩坑的地方却不少。这里整理几个高频问题:
- 图片、视频不要放进压缩类型,它们本身就是压缩格式,强行压缩只会浪费 CPU
- 已压缩的响应(如反向代理上游已压缩过)避免二次压缩,可在 location 里关掉 gzip 或用
proxy_set_header Accept-Encoding "" - 改完配置一定要
nginx -t检查语法再 reload,语法错误会导致整个站点 502 - 别把
gzip_comp_level调到 9,除非你的 CPU 非常空闲,否则在高并发下反而拖慢响应 - 动态接口(JSON API)也建议压缩,但要注意接口本身是否已经很小,
gzip_min_length能帮你自动跳过小响应
如果你的服务器同时承担多站点 HTTPS 与反向代理,压缩之外还要关注 TLS 与证书的稳定性,可以参考 Certbot 证书续期排障 一并做周期巡检,避免证书过期导致的访问中断抵消掉压缩带来的提速。
总结
Nginx gzip 与 Brotli 压缩是性价比最高的传输优化手段之一,改几行配置就能降低带宽占用、缩短页面加载时间,而且几乎不改变站点结构。落地步骤很清晰:先在 http 块开启 gzip 并配好 MIME 类型与压缩级别,再按需编译安装 ngx_brotli 模块开启 Brotli,最后用 curl 验证 Content-Encoding 和压缩率。记住文本类资源才值得压缩、级别取 5 到 7 的典型区间、配合浏览器缓存与监控面板持续观察,就能稳定拿到压缩带来的提速收益。如果你需要一台性能稳定、带宽配置灵活的海外服务器来承载高并发压缩传输,Hostease 的 VPS(Virtual Private Server,虚拟专用服务器,通过虚拟化技术在一台物理机上划分出的独立服务器环境)与独立服务器方案都可以满足部署需求,但具体压缩参数仍建议按本文清单结合自身流量实测后确定。
