压缩

OxPHP 默认使用 Brotli 编码压缩 HTTP 响应。只要客户端支持,它就会自动应用于基于文本的内容类型,因此无需改动应用代码,传输体积就会下降。

工作原理

在 OxPHP 决定是否压缩某个响应之前,每个响应都会按顺序经过以下相同的检查:

  1. Accept-Encoding 检查。 解析客户端的 Accept-Encoding 请求头,判断是否支持 br(Brotli)。该请求头中不含 br 的请求永远不会被压缩。
  2. 内容类型检查。 对照可压缩类型列表核对响应的 MIME 类型。
  3. 已编码检查。 已带有 Content-Encoding 请求头的响应会被跳过,以避免二次压缩。
  4. 大小范围检查。 只有介于 256 字节和 3 MB 之间的响应才会被压缩。更小的响应收益甚微;更大的响应则以流式方式发送,不做缓冲。
  5. 压缩。 应用 Brotli 编码。如果压缩后的输出并不比原始内容更小,则改为发送未压缩的响应。
Note

压缩发生在 PHP 执行之后、静态文件服务之后。整个压缩后的响应体会短暂驻留在内存中,这也是为什么超过 3 MB 的响应会被排除在外。

配置

变量 默认值 描述
COMPRESSION_LEVEL 4 Brotli 质量级别(0–11)。数值越高,输出越小,但会消耗更多 CPU 时间。设为 0 可完全禁用压缩

默认级别 4 在压缩率与 CPU 占用之间取得了平衡,适合 Web 服务场景。级别 9–11 更适合离线或构建期的压缩。

可压缩的内容类型

压缩适用于以下 MIME 类型:

Text 类型:

  • text/html
  • text/css
  • text/plain
  • text/xml
  • text/javascript

Application 类型:

  • application/javascript
  • application/json
  • application/xml
  • application/xhtml+xml
  • application/rss+xml
  • application/atom+xml
  • application/manifest+json
  • application/ld+json
  • application/wasm

其他类型:

  • image/svg+xml
  • font/ttf
  • font/otf
  • application/x-font-ttf
  • application/x-font-opentype
  • application/vnd.ms-fontobject

不会被压缩的情况

当满足以下任一条件时,响应将不经压缩直接发送:

  • 客户端未在 Accept-Encoding 请求头中声明 br
  • 响应已带有 Content-Encoding 请求头(例如预压缩内容)
  • 响应体小于 256 字节或大于 3 MB
  • 内容类型不在可压缩列表中(例如 image/pngimage/jpegfont/woff2application/zip——这些格式本身已使用内部压缩)
  • 响应以流式方式发送——在发送请求头时其长度未知(使用 oxphp_stream_flush() 的 PHP 脚本、Server-Sent Events)。压缩一个流需要将其完整缓冲到内存中,会破坏首字节到达时间,因此流式响应始终原样不压缩地通过

响应头

应用压缩时,OxPHP 会设置以下请求头:

请求头
Content-Encoding br
Content-Length 更新为压缩后的响应体大小
Vary 追加 Accept-Encoding,确保 HTTP 缓存为支持和不支持 Brotli 的客户端分别存储不同版本

疑难排查

响应没有被压缩

确认客户端发送了 Accept-Encoding: br。大多数现代浏览器都会发送,但某些 HTTP 测试工具默认不包含它。

使用 curl 检查

bash
curl -H "Accept-Encoding: br" -I http://localhost/

在响应头中查找 Content-Encoding: br。如果缺失,请检查:

  1. COMPRESSION_LEVEL 未被设为 0
  2. 响应体至少有 256 字节
  3. 响应的 Content-Type 在上述可压缩列表中
压缩反而让响应变大了

对于非常小的响应(几百字节以内),Brotli 的开销偶尔会产生比原始内容更大的输出。OxPHP 会检测到这一点并自动发送未压缩的响应——无需更改任何配置。

压缩导致 CPU 占用过高

更高的质量级别(8–11)压缩效果明显更好,但会消耗多得多的 CPU。如果你观察到压缩带来的高 CPU 消耗:

修复方法:COMPRESSION_LEVEL 降到 45。这些级别能以极小的 CPU 代价,达到最高质量级别 80–90% 的体积缩减效果。

预压缩的资源被再次压缩

如果你的构建流程生成了 .br 文件并为这些文件设置了 Content-Encoding: br 请求头,OxPHP 会自动跳过重复压缩。如果你的预压缩内容仍被再次压缩,请确认在压缩运行之前,原始响应中已存在 Content-Encoding 请求头。

Docker 示例

compose.yaml
services: app: image: ghcr.io/oxphp/oxphp:0.10.0 ports: - "8080:80" volumes: - ./src:/var/www/html environment: - DOCUMENT_ROOT=/var/www/html/public - ENTRY_FILE=index.php - COMPRESSION_LEVEL=6

另请参阅