Composer镜像必须用Gzip或Brotli,因客户端依赖cURL解压:Brotli需libcurl 7.57.0+且编译启用HAVE_BROTLI(PHP 8.0+/Alpine 3.16+默认支持,但Windows旧版PHP常不支持),而Gzip所有PHP+cURL组合均原生支持。

Composer 镜像源(如阿里云、腾讯云、华为云)在分发 composer.lock、packages.json 和 ZIP 包元数据时,普遍启用服务端压缩。Gzip 和 Brotli(brotliCompress)是当前实际部署中唯二被广泛支持的两种算法——deflate 因无校验、易出错、Nginx/Apache 原生支持弱,基本不在镜像源生产环境使用。
为什么 Composer 镜像必须用 Gzip 或 Brotli?
Composer 客户端(PHP CLI)通过 HTTP 请求获取远程 JSON 元数据(如 https://mirrors.aliyun.com/composer/p2/monolog/monolog.json),这些响应体全是纯文本,体积常达 100–500KB。不压缩时,单次请求可能多传 300KB;对依赖树深的项目,元数据请求数可达数十次。压缩直接决定 composer install 的首屏等待时间和失败率(尤其在弱网或高延迟区域)。
关键点在于:composer 自身不主动协商或解压 br;它完全依赖 PHP cURL 扩展和底层 libcurl 的能力。而 libcurl 对 br 的支持从 7.57.0 开始,且需编译时启用 HAVE_BROTLI。这意味着:
- PHP 8.0+ 默认编译的 cURL 多数已含 Brotli 支持(如 Ubuntu 22.04+、Alpine 3.16+)
- 但 Windows 上的 XAMPP、WAMP、旧版 Docker PHP 镜像(如
php:7.4-apache)大概率不带brotli,此时即使镜像源返回Content-Encoding: br,cURL 会静默忽略或报错Unsupported encoding type 'br' -
gzip则无此问题:所有 PHP 版本 + cURL 组合都原生支持
Nginx 配置 Brotli 时最容易踩的三个坑
镜像源后端多用 Nginx,启用 Brotli 需手动编译 ngx_brotli 模块(官方未内置)。常见误配导致实际无效:
- 漏加
brotli on;—— 即使配置了brotli_comp_level和brotli_types,没开总开关等于没配 -
brotli_types没包含application/vnd.php.serialized—— Composer 的某些二进制序列化响应(如部分私有仓库)用此 MIME 类型,不加则不压缩 - 与
gzip规则共存时未设gzip_vary on和brotli_vary on—— CDN 或反向代理可能缓存 gzip 版本并错误返回给支持 br 的客户端
正确最小配置示例:
http {
brotli on;
brotli_comp_level 6;
brotli_types application/json application/vnd.php.serialized text/plain text/css text/javascript;
brotli_vary on;
gzip on;
gzip_vary on;
gzip_comp_level 6;
gzip_types application/json application/vnd.php.serialized text/plain text/css text/javascript;
}
如何验证镜像源是否真在用 Brotli?
别信文档,直接看响应头。用 curl -I -H "Accept-Encoding: br,gzip" 请求任意 packages.json:
- 若返回
Content-Encoding: br且Vary: Accept-Encoding→ Brotli 生效 - 若返回
Content-Encoding: gzip→ 可能是客户端不支持 br,或 Nginx 未匹配到brotli_types,或上游 CDN 强制降级 - 若返回空
Content-Encoding→ 压缩完全未启用,检查 Nginx error log 中是否有unknown directive "brotli"(模块未加载)
注意:Accept-Encoding: br,gzip 必须显式带上,否则某些 CDN(如 Cloudflare 免费版)默认只返回 gzip,即使源站支持 br。
Brotli 在 Composer 镜像场景下收益明确:JSON 元数据平均再小 15%–22%,但它的脆弱性也真实存在——一端不支持就退化为 gzip,而这个“一端”可能是你 CI 流水线里那个没更新的 PHP 镜像,也可能是某台离线打包机上的旧版 WampServer。所以生产镜像源必须双开,且把 gzip 当 fallback 而非备选。











