codeigniter 4 默认不启用 gzip 压缩,需手动设置 app\config\headers::$compressoutput = true,并确保 php zlib.output_compression 关闭、web 服务器(如 nginx/apache)不重复压缩,且 profiler 关闭以避免干扰。

CodeIgniter 4 如何启用 Gzip 响应压缩
默认不开启,必须手动配置;否则 Content-Encoding: gzip 不会出现,前端收不到压缩响应。
关键在 App\Config\Headers 和底层 SAPI 检测逻辑:CI4 只在 CLI 环境下默认禁用压缩,但 Web 环境仍需显式开启,且依赖 PHP 的 zlib.output_compression 或 ob_gzhandler。
- 打开
app/Config/Headers.php,确认$compressOutput = true已设为true - 检查 PHP 配置:运行
php -i | grep zlib,确保zlib.output_compression为Off(CI4 自己接管压缩,开启它反而冲突) - 若用 Apache,确认
mod_deflate未重复压缩——CI4 输出已压缩时,Apache 再压一次会损坏响应体
CodeIgniter 3 的 output->enable_profiler() 会干扰压缩
开启调试工具条后,output->enable_profiler(true) 会强制关闭输出缓冲链路中的 gzip 处理,导致压缩失效,且无任何警告。
这不是 Bug,是设计取舍:Profiler 需要完整原始 HTML 插入脚本,而 ob_gzhandler 的缓冲不可逆读取。
- 上线前务必确认
$this->output->enable_profiler(FALSE)或注释掉相关行 - 开发时想兼顾压缩与调试?改用浏览器 Network 面板看
Content-Encoding,别依赖 Profiler 显示 - 自定义中间件或钩子中调用
ob_start('ob_gzhandler')会与 CI3 内置压缩冲突,优先用框架原生开关
为什么设置了压缩却看不到 Content-Encoding: gzip
常见于 Nginx 反向代理场景:CI 输出了压缩内容,但 Nginx 默认对非 200 响应、小响应(gzip_min_length)、或特定 MIME 类型(如 application/json)跳过解包/透传。
此时浏览器收到的是 gzip 字节流,但响应头没声明,解析失败,表现为白屏或 JSON 解析错误。
- 检查 Nginx 配置:确认有
gzip_vary on;和gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; - CI 中输出 JSON 时,确保
Content-Type是application/json(不是text/html),否则 Nginx 不触发 gzip 匹配 - 用
curl -I -H "Accept-Encoding: gzip" http://yoursite.com/api直接测响应头,绕过浏览器缓存干扰
PHP zlib.output_compression 和 CI 压缩共存的坑
两者都启用时,响应会被压两次:第一次由 PHP 内置 zlib,第二次由 CI 的 ob_gzhandler,结果是乱码或 Content-Length 错误,Chrome 直接报 ERR_CONTENT_DECODING_FAILED。
CI 文档没明说这点,但源码里 System/HTTP/Response.php 的 send() 方法会检测 ini_get('zlib.output_compression'),为非零值时直接跳过自身压缩。
- 执行
php -r "echo ini_get('zlib.output_compression');",输出应为0或空 - 若用 Docker,检查
php.ini是否在镜像层被覆盖(如php:apache默认开 zlib) - 共享主机环境无法改 php.ini?在
public/index.php开头加ini_set('zlib.output_compression', '0');强制关闭
压缩是否生效,不能只看代码开了没,得盯住三处:PHP 的 zlib 设置、框架的开关变量、反代服务器的 gzip 规则。少一个,就白配。










