Webman中禁用StaticFile中间件,由Nginx直出静态文件:因PHP层readfile()触发四次拷贝与框架开销,QPS仅1100;而Nginx sendfile零拷贝可达25000,且需配置location拦截后缀、try_files $uri =404及immutable缓存头。

Webman 里用 PHP 直接 serve 静态文件(比如 readfile() 输出 CSS/JS/图片)是性能黑洞,QPS 掉到 1200 以下、延迟飙到 40ms+,这不是配置问题,是架构误用——必须让 Nginx 直出,PHP 只管动态逻辑。
为什么不能在 Webman 中用 StaticFile 中间件服务生产静态资源
Webman 的 app\middleware\StaticFile::class 本质是 PHP 层拦截 + 文件读取,它绕不开 SAPI 生命周期:每次请求都要加载框架、解析路由、执行中间件链、调用 readfile()、拼响应头。这和 Nginx 原生 sendfile() 零拷贝直出完全不是一个量级。
- 实测对比:同服务器下,Nginx 直出 JS 文件 QPS ≈ 25000,Webman
StaticFile中间件仅 ≈ 1100 -
Cache-Control和ETag很难精准生成,尤其在容器挂载或软链接路径下,浏览器协商缓存常失效 - CDN 回源时若收到 PHP 返回的响应,因缺少
public, immutable,很可能拒绝缓存或只缓存几秒 - 该中间件默认禁用
.env、.git等隐藏文件,但无法替代 Nginx 的location级别路径过滤和安全加固
Nginx 必须拦截静态后缀并直出(关键 location 规则)
真正生效的配置不在 Webman 里,而在 Nginx 的 server 块中。重点不是“有没有写”,而是是否被覆盖、是否顺序靠前、是否含 try_files。
- 把以下配置放在
server块内、与root同级,**不要嵌套在location /或location ~ \.php$里** - 必须放在 PHP 处理规则(如
fastcgi_pass)之前,否则请求先被转发给 PHP-FPM -
try_files $uri =404是刚需:防止/logo.png/xxx这类非法路径 fallback 到 PHP 路由,造成意外交互
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2|ttf|eot|webp|pdf|xml|txt)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
add_header X-Content-Type-Options nosniff;
try_files $uri =404;
}Webman 配置只需关掉静态中间件,不参与响应
既然 Nginx 已接管所有静态请求,Webman 就不该再碰这些路径。否则可能冲突(比如 Nginx 返回 200,Webman 中间件又返回 403),或浪费 CPU 做无用判断。
立即学习“PHP免费学习笔记(深入)”;
- 检查
config/static.php,确保'enable'为false,或直接注释掉app\middleware\StaticFile::class - 确认 Webman 的路由没定义类似
GET /static/*或GET /assets/*的通配规则,避免意外捕获 - 如果用了 CDN,前端构建时必须设
publicPath指向 CDN 域名(如https://static.example.com/),否则 HTML 中仍引用/css/app.css,请求根本不会走到 Nginx 的静态规则里
immutable 缓存头不是可选项,是现代前端的必需条件
只写 max-age=31536000 不够。浏览器和 CDN 对带哈希指纹的资源(如 app.a1b2c3.js)需要 immutable 才能跳过 If-None-Match 协商请求——少一次 RTT,首屏快 100ms+。
- 绝对不要用
private或no-cache:静态资源是公开的,CDN 和代理必须能缓存 - 如果项目没做文件名哈希(还在用
main.css),immutable会带来更新风险,此时应降级为max-age=3600并配合版本号参数(如main.css?v=2.1.0) - 验证是否生效:用
curl -I https://yoursite.com/app.js,看响应头是否含Cache-Control: public, max-age=31536000, immutable
真正卡住速度的从来不是 Webman 配置多复杂,而是 Nginx 的 location 是否真的拦截了请求、immutable 是否随响应发出、前端 URL 是否指向了正确入口——这三个点漏一个,优化就归零。



















