发布时间:2026-09-17 12:31 更新时间:2026-09-17 12:31 阅读量:0
网站打开慢,很多人第一反应是换更大的带宽或者上 CDN,其实有一项改动成本极低、收益却很明显:把 HTML、CSS、JS、JSON 这些文本资源在传输前压缩一遍。一份 300KB 的 JavaScript,压缩后往往只剩 80KB 左右,首屏加载时间能实打实地缩短。Nginx 原生支持 gzip,Brotli 则需要额外模块,两者可以同时开启。本文从模块加载讲到 MIME 白名单,把「开了却没生效」的常见坑一并说清楚。
gzip 是 Nginx 自带的功能,不需要装模块,在 http、server 或 location 块里都能写。新手容易只写一句 gzip on;,结果发现压缩没起什么作用,原因是默认的 gzip_types 只包含 text/html,而 HTML 通常本来就很小,真正的大头 CSS 和 JS 根本没被压。
一段可以直接抄的配置如下,放在 server 块内即可,注意 gzip_types 里不要重复写 text/html,Nginx 会提示告警:
gzip on;
gzip_comp_level 5;
gzip_min_length 1k;
gzip_vary on;
gzip_proxied any;
gzip_types
text/plain
text/css
text/xml
application/json
application/javascript
application/x-javascript
application/xml
application/rss+xml
image/svg+xml;
几个关键参数的含义值得展开说。gzip_comp_level 取值 1 到 9,数字越大压得越小但越费 CPU。实践中 5 到 6 是比较舒服的平衡点,从 6 提到 9,文件体积通常只再小几个百分点,CPU 占用却明显上升,以实际压测为准。gzip_min_length 用来避免对小文件做无用功,小于 1KB 的响应压完可能反而更大。gzip_vary 会输出 Vary: Accept-Encoding 头,告诉 CDN 和代理按是否支持压缩分别缓存,漏了这个头容易让 CDN 缓存串味。gzip_proxied any 则解决走 CDN 回源时请求带 Via 头导致不压缩的问题。
需要提醒的是,压缩是消耗 CPU 换带宽。如果服务器本身 CPU 就很紧张,把级别调到 9 可能让 TTFB 变差。判断办法是改完配置后用浏览器开发者工具的 Network 面板看 Content-Encoding 和 Size 两列,再用 ab 或 wrk 做一次简单压测对比,具体数值以自己环境为准。
Brotli 在文本资源上的压缩率普遍比 gzip 高,代价是压缩时 CPU 消耗更大、浏览器支持面稍窄(现代主流浏览器基本都支持)。Nginx 默认不带 Brotli,需要编译 ngx_brotli 模块,或者用发行版/面板提供的现成包。版本与安装方式差异较大,务必以 ngx_brotli 官方仓库和所用系统的文档为准,不要照搬来源不明的二进制包。
模块加载成功后,可以这样配置:
brotli on;
brotli_comp_level 5;
brotli_min_length 1k;
brotli_types
text/plain
text/css
application/json
application/javascript
image/svg+xml;
这里有个很多人忽略的点:动态压缩和静态预压缩是两回事。动态压缩是每次请求现压,适合 HTML 这种频繁变化的内容;而 CSS、JS 这类打包后基本不变的文件,更适合在部署阶段用 brotli 命令行工具提前压成 .br 文件,再让 Nginx 直接返回,几乎不占运行期 CPU。开启方式就是加一行 brotli_static on;,Nginx 会优先查找同名 .br 文件。gzip 也有对应的 gzip_static on;,两者可以并存,Nginx 按客户端支持情况挑一个返回。
部署脚本里可以顺手加上预压缩步骤,路径按自己项目调整:
find /www/wwwroot/example.com/static -type f \
\( -name '*.css' -o -name '*.js' -o -name '*.svg' \) \
-exec brotli -q 11 -f {} \;
find /www/wwwroot/example.com/static -type f \
\( -name '*.css' -o -name '*.js' -o -name '*.svg' \) \
-exec gzip -9 -k -f {} \;
注意 -k 是保留原文件,否则 gzip 会把源文件删掉,这个坑踩一次就够记一辈子。预压缩文件要和源文件放在同一目录,Nginx 才能按规则找到。
配置写完 curl 一下最直接,重点看响应头里有没有 Content-Encoding。命令如下,-H 用来模拟浏览器声明支持 br 和 gzip:
curl -I -H 'Accept-Encoding: br,gzip' https://www.example.com/static/app.js
如果返回头里没有 Content-Encoding,按下面几条依次核对。第一,确认请求的资源类型在 gzip_types 或 brotli_types 白名单里,MIME 类型必须与响应头 Content-Type 完全对得上,application/x-javascript 和 application/javascript 是两种写法,很多老配置只写了前者。第二,看文件是否小于 gzip_min_length 设置的阈值。第三,如果前面挂了 CDN,要确认 CDN 侧是否也开了压缩、是否把源站的 Content-Encoding 头覆盖掉,回源请求头是否被改写。第四,检查是不是被更靠前的 location 规则接管了,比如某些面板会给静态目录单独写一段 location,里面没有继承压缩配置——Nginx 的指令继承是按块生效的,父块开了不一定子块也开。
还有一类问题不是「没压」而是「压了反而慢」。已经压过的图片(JPEG、PNG、WebP)、视频、音频、字体里的 woff2,本身已是压缩格式,再过一遍 gzip 基本不减小,纯属浪费 CPU,所以这些类型不要放进白名单。PDF、zip 同理。真正值得压的是 HTML、CSS、JS、JSON、XML、SVG 和纯文本接口返回,体积大、重复度高,压缩收益最明显。
最后给一个落地顺序:先只开 gzip,把 gzip_types 补齐并验证生效,观察一周 CPU 与响应时间;确认没问题再上 Brotli,静态资源尽量走预压缩;CDN 场景下别忘了 gzip_vary 和两端压缩策略的一致性。压缩不是一次性开关,而是随着资源结构变化需要回看的配置项,改完记得用 curl 或浏览器 Network 面板复核一遍,别只看配置文件里写了 on 就放心。
| 📑 | 📅 |
|---|---|
| 同一台服务器跑多个网站:Nginx server_name 匹配顺序与默认站点防串站配置 | 2026-09-17 |
| WordPress图片站提速:WebP批量转换、懒加载与Nginx静态直返 | 2026-09-17 |
| 网站被恶意刷流量刷接口怎么办:Nginx限速与IP封禁配置思路 | 2026-09-17 |
| 宝塔面板网站防跨站攻击open_basedir怎么配:报错原因、目录放行与多站隔离实践 | 2026-09-17 |
| 服务器时间不对导致HTTPS报错与定时任务错乱:ntp/chrony校时与宝塔同步配置实操 | 2026-09-16 |
| 宝塔面板 Nginx 与 Apache 该选哪个:并发模型差异与切换后伪静态失效处理 | 2026-09-17 |
| 网站图片被外站盗链怎么办:Nginx防盗链配置与误伤排查 | 2026-09-17 |
| WordPress后台打开极慢前台正常:插件钩子与admin-ajax排查 | 2026-09-17 |
| WordPress定时发布失效排查:wp-cron不触发与服务器计划任务替代方案 | 2026-09-18 |
| 301跳转链太长拖慢首屏:curl与浏览器面板揪出重定向链 | 2026-09-18 |