Brotli压缩与Nginx缓存必须协同配置才能发挥最佳效果:单独启用任一功能性能减半;需确认Nginx已编译ngx_http_brotli_filter_module模块,禁用gzip避免协商冲突,在http块启用brotli并合理设置参数,为/static/路径配置immutable缓存与ETag,并替换精简版app.js以减少首屏体积。

Brotli 压缩 + Nginx 缓存必须一起配,单开任一个效果都打对折——Brotli 能压小文件体积,但没缓存的话每次还得走完整请求链;有缓存但没 Brotli,静态资源仍以未压缩形态反复传输。
确认 Nginx 已编译支持 Brotli 模块
宝塔默认 Nginx 不带 ngx_brotli,光在后台点“开启 Brotli”没用。必须验证模块真实存在:
- 执行
nginx -V 2>&1 | grep -o ngx_http_brotli_filter_module,有输出才说明模块已编译进二进制 - 若为空,别跳过这步——先卸载当前 Nginx(宝塔软件商店 → 已安装 → Nginx → 卸载),再【编译安装】并勾选自定义模块
--add-module=/www/server/ngx_brotli - 注意:
ngx_brotli依赖libbrotli,宝塔编译流程会自动处理;手动编译时需确保./configure参数末尾加了--with-compat,否则make install可能失败
在 http 块中启用 Brotli 并禁用 gzip 冲突
Brotli 和 gzip 共存看似合理,但实际会导致 Nginx 优先选 gzip(尤其旧客户端协商时),且 gzip_vary on 与 brotli 的 Vary: Accept-Encoding 行为不一致,容易缓存错乱。
- 进入【软件商店】→ Nginx → 【设置】→ 【配置修改】,在
http {块开头后插入(务必在所有server块之前): brotli on;-
brotli_comp_level 6;(5–7 是平衡点,9 会显著拖慢高并发响应) -
brotli_min_length 512;(太小的响应不值得压缩,避免 CPU 白耗) brotli_types text/plain text/css application/javascript application/json text/html image/svg+xml image/x-icon font/opentype;- 删掉或注释掉全局
gzip on;及其相关行——不是“关闭 gzip”,而是彻底移除,防止协商冲突
给 /static/ 路径加强缓存 + ETag
宝塔面板自身 JS/CSS 文件(如 /static/app.js)无版本哈希,靠 Cache-Control: immutable 强缓存 + ETag 校验最稳妥。只配 max-age 不够,Chrome 对无哈希文件会强制 revalidate。
- 在站点配置的
location /static/ {块内添加: add_header Cache-Control "public, max-age=31536000, immutable";etag on;-
expires off;(必须关掉,否则和immutable冲突,导致 Chrome 降级为no-cache) - 别在
http块里全局写expires,它会覆盖location级别的Cache-Control
替换精简版 app.js 减少首屏 JS 体积
官方 app.js 包含 Docker、MongoDB、监控等你大概率不用的模块,实测可从 2.1MB(gzip)压到 320KB(br)。但直接删代码易报 Cannot find module './xxx' 错误。
- 先备份:
cp /www/server/panel/static/app.js /www/server/panel/static/app.js.bak - 用预构建轻量版替换(仅保留网站、FTP、防火墙、SSL 四个核心路由):
wget -O /www/server/panel/static/app.js https://cdn.example.com/bt-lite-app.js(链接需自行替换为可信源) - 替换后清浏览器缓存,访问
/static/app.js?t=1查响应头:Content-Encoding: br+Cache-Control: public, max-age=31536000, immutable同时存在才算生效 - 若控制台报模块缺失,退回原文件,改用
sed删除非必要import行(如monitor、security相关路由),而非整块删功能代码
真正卡顿往往不在压缩或缓存本身,而在 Brotli 配置位置错了(写进了 server 块)、immutable 和 expires 并存、或轻量版 app.js 没关掉宝塔后台的“检查更新”轮询——那个每 30 秒一次的 /api/panel/get_soft_list 请求,会持续抢占 TCP 连接,让真实页面请求排队。


















