Brotli兼容性依赖Accept-Encoding协商而非UA判断:客户端声明br则返回br,仅声明gzip则返回gzip,未声明则不压缩;必须保留gzip配置以兜底IE等旧环境,禁用gzip会导致无压缩fallback。

旧版本浏览器不支持 Brotli,Nginx 本身不做 UA 判断,而是严格依赖 HTTP 标准协商机制——靠客户端在 Accept-Encoding 请求头中声明能力。只要浏览器没发 br,Nginx 就不会尝试用 Brotli 编码,自然不会出错。
兼容性靠 Accept-Encoding 自动兜底,不是靠降级逻辑
Brotli 和 Gzip 在 Nginx 中是并存、非互斥的配置。服务器不主动“选择”或“切换”,只响应客户端明确声明的支持项:
- 请求头含
Accept-Encoding: br, gzip(Chrome/Firefox/Edge/Safari 16.4+)→ Nginx 返回Content-Encoding: br - 请求头只有
Accept-Encoding: gzip(IE、Android 4.4 WebView、旧版 Safari)→ Nginx 返回Content-Encoding: gzip - 请求头为空或仅
identity→ 不压缩,原样返回
必须保留 Gzip 配置,且不能禁用
即使全站已启用 Brotli,gzip on 仍需保持开启。原因有三:
- IE 11 及更早版本完全忽略
br,只认gzip - 部分企业内网代理、老旧 CDN 节点会清洗或重写
Accept-Encoding,删掉br - Nginx 的压缩模块互不干扰:brotli 指令只对带
br的请求生效,其余交由 gzip 模块处理
验证兼容性是否真正落地
不要只看现代浏览器,重点测试典型旧环境:
- 用 IE 11 或 Windows 7 虚拟机访问,检查响应头是否为
Content-Encoding: gzip - 用 curl 模拟旧请求:
curl -H "Accept-Encoding: gzip" -I https://yoursite.com/app.js,确认返回 gzip - 查看 Nginx error.log 是否有
unknown directive "brotli"—— 若有,说明模块未编译成功,此时所有请求都会 fallback 到无压缩状态,比 gzip 更差
不推荐、也不需要手动 UA 过滤
有人试图用 map $http_user_agent $brotli_flag 做 UA 匹配来开关 Brotli,这反而破坏标准流程:
- UA 字符串易伪造、难维护,Safari 15 和 16.4 对 br 的支持边界模糊
- 绕过 Accept-Encoding 协商后,CDN 或中间代理可能缓存错版本(Vary 头失效)
- HTTP/2 环境下,客户端协商更可靠,UA 判断纯属冗余











