webman 的 staticfile 中间件默认不压缩静态文件,因其职责限于路径校验、安全拦截和基础响应头设置,不处理内容编码;且 readfile() 等流式输出绕过 php 输出缓冲,ob_gzhandler 无效,手动 gzencode() 易致内存溢出与响应头错误。

Webman 本身不提供内置的静态文件 GZIP 压缩输出能力,必须手动集成或交由前置服务器处理;直接在 PHP 层对 file_get_contents() 后的数据调用 gzencode() 是低效且危险的。
为什么 Webman 的 StaticFile 中间件默认不压缩静态文件
StaticFile 中间件的核心职责是路径校验、安全拦截(如拒绝 /.env)、设置基础响应头(Content-Type、Cache-Control),它不介入内容体的编码变换。PHP 的输出缓冲压缩(如 ob_gzhandler)只对 echo/print 输出生效,而 StaticFile 使用的是 readfile() 或 stream_copy_to_stream() 直接刷文件流——这类操作绕过输出缓冲,ob_start('ob_gzhandler') 完全无效。
- 尝试在
process()中手动gzencode(file_get_contents($path)):会把整个文件读进内存,大文件(>10MB)直接触发 OOM 或阻塞 Worker - 用
gzencode()压缩后再header('Content-Encoding: gzip'):必须同步修改Content-Length,否则浏览器解压失败或白屏 - 未校验客户端是否支持
gzip:对不带Accept-Encoding: gzip的请求也发 gzip,导致乱码
真正可行的静态压缩方案只有两种
Webman 不是 Web 服务器,它的定位是「动态逻辑网关」。静态资源压缩这件事,应该交给更专业的角色来做:
-
Nginx 前置 +
gzip_static on:提前用gzip -k style.css生成style.css.gz,Nginx 检测到请求头支持 gzip 且存在同名 .gz 文件时,自动返回并加Content-Encoding: gzip头——零 PHP 开销,内核级高效 -
Nginx 动态压缩 +
gzip on:对未预压缩的文件实时压缩,需配置gzip_types显式声明text/css application/javascript image/svg+xml等 MIME 类型,避免图片二次压缩(JPEG/PNG 本身已压缩) - CDN 层压缩(如 Cloudflare、阿里云 CDN):开启「自动 GZIP」后,CDN 节点对回源获取的未压缩资源做边缘压缩,源站无需任何改动
如果硬要在 Webman 中临时启用压缩(仅限小文件/调试)
仅建议用于权限校验后的小体积资源(如用户私有 PDF、加密 JS 配置),且必须满足以下条件:
- 文件大小严格限制在
2MB以内(防止内存暴涨) - 必须检查
$_SERVER['HTTP_ACCEPT_ENCODING']是否含gzip - 必须用
gzencode($data, 6)(非gzcompress,后者格式不被浏览器识别) - 必须重写
Content-Length和Content-Encoding,例如:header('Content-Encoding: gzip'); header('Content-Length: ' . strlen($compressed)); echo $compressed; - 禁用
Cache-Control: no-cache,否则浏览器不会缓存压缩后的内容
最常被忽略的一点:Nginx 的 gzip_static 只匹配精确文件名,不会自动 fallback 到未压缩版本。如果配置了 gzip_static on 但忘了生成 .gz 文件,请求会直接 404。上线前务必用 curl -H "Accept-Encoding: gzip" -I http://yoursite.com/style.css 验证响应头是否含 Content-Encoding: gzip。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











