Mezzio是PHP生态中一个遵循PSR-15规范的微框架,前身是Zend Expressive。它的核心设计理念是把HTTP请求到响应的整个过程,拆解为若干个可复用、可排序的中间件,每一个中间件只关心自己那一层的逻辑,比如鉴权、日志、路由或者具体业务处理。这种结构让应用不再被笨重的全栈框架绑架,开发者可以按需要挑选路由库、容器库和模板引擎。理解Mezzio的运作方式,关键在于弄清它如何依据PSR-15标准去调度中间件管道。

PSR-15规范与Mezzio核心概念解析
PSR-15定义了两种核心接口:MiddlewareInterface和RequestHandlerInterface。前者要求实现process()方法,接收ServerRequestInterface和RequestHandlerInterface,返回ResponseInterface;后者要求实现handle()方法,仅接收请求并返回响应。在Mezzio中,管道(pipeline)本质是一个队列,请求依次穿过队列里的中间件,直到某个中间件生成响应并反向传回。这种双向流动模型,和传统框架的单向过滤器不同,它允许中间件在调用$handler->handle()前后都插入逻辑。
Mezzio并不强制你使用特定路由或容器,它只提供骨架和调度器。比如默认骨架会用Laminas Stratus容器或者PHP-DI,路由可选FastRoute、Laminas Router等。这种解耦带来灵活性,但也要求开发者明白各组件如何被组装进Application实例。当请求进入时,Application自身充当最外层的RequestHandler,把请求交给管道头节点,逐层下沉。
另一个容易混淆的点是中间件与请求处理器的职责边界。很多初学者把全部逻辑写进一个中间件,导致管道失去分层意义。正确做法是:管道前半段做跨切面处理,如CORS、会话启动;路由中间件匹配后,将请求转交具体处理器或控制器中间件。这样每一层都可被单独测试和替换,符合PSR-15的可组合精神。
从Composer骨架开始搭建基础应用
最快捷的起步方式是使用官方骨架包。执行composer create-project mezzio/mezzio-skeleton后,命令行会交互询问使用的容器、路由器、模板等。选完之后,目录里会出现config文件夹,里面用配置文件声明中间件管道顺序。骨架默认已经把错误捕获中间件、路由中间件放进管道,你只需在src/App/src/Handler下写自己的业务处理器。
如果希望手动控制而非依赖骨架生成,可以只引入mezzio/mezzio核心包,然后自行编排。下面是一段最小可用的引导代码,展示如何把多个中间件压入管道并运行:
<?php
use MezzioApplication;
use MezzioMiddlewareFactory;
use LaminasDiactorosResponse;
use LaminasDiactorosServerRequestFactory;
use PsrHttpMessageServerRequestInterface;
use PsrHttpMessageResponseInterface;
use PsrHttpServerRequestHandlerInterface;
use PsrHttpServerMiddlewareInterface;
// 自定义日志中间件
class LogMiddleware implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
error_log('请求进入:' . $request->getUri()->getPath());
$response = $handler->handle($request);
return $response;
}
}
// 简单响应处理器
class HomeHandler implements RequestHandlerInterface
{
public function handle(ServerRequestInterface $request): ResponseInterface
{
$response = new Response();
$response->getBody()->write('Hello Mezzio');
return $response;
}
}
require __DIR__ . '/vendor/autoload.php';
$app = new Application(
new MiddlewareFactory(null),
new class implements RequestHandlerInterface {
public function handle(ServerRequestInterface $request): ResponseInterface {
$r = new Response();
$r->getBody()->write('未匹配');
return $r;
}
}
);
$app->pipe(new LogMiddleware());
$app->run(new HomeHandler());
$request = ServerRequestFactory::fromGlobals();
$app->handle($request);
上面代码里,pipe()方法把日志中间件加入管道,run()设定默认处理器。虽然示例为了简洁没有完全接驳路由器,但已经体现出Mezzio调度的最小形态。实际项目中,我们会用$app->route()来绑定URI与处理器,而非把所有请求都交给同一个HomeHandler。
配置文件方面,骨架采用的config/pipeline.php返回闭包,接收Application对象并调用pipe。这样做的好处是把管道定义集中管理,避免引导文件膨胀。你可以通过调整pipe调用的先后顺序,控制比如先解析Body再鉴权,还是先鉴权再解析,顺序错乱常导致拿不到表单数据或权限误判。
编写并注册自定义PSR-15中间件
在Mezzio里写中间件有两种常见风格:类实现MiddlewareInterface,或者用闭包配合MiddlewareFactory。类形式更适合复杂逻辑和依赖注入,闭包则适合一次性过滤。下面示例展示一个鉴权中间件类,它检查请求头里的Token,失败就直接返回401,不再往下传递。
<?php
use PsrHttpMessageServerRequestInterface;
use PsrHttpMessageResponseInterface;
use PsrHttpServerRequestHandlerInterface;
use PsrHttpServerMiddlewareInterface;
use LaminasDiactorosResponseJsonResponse;
class AuthMiddleware implements MiddlewareInterface
{
private array $validTokens;
public function __construct(array $validTokens)
{
$this->validTokens = $validTokens;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$token = $request->getHeaderLine('X-Api-Token');
if (!in_array($token, $this->validTokens, true)) {
return new JsonResponse(['error' => '无权访问'], 401);
}
// 通过鉴权,把解析出的用户附到请求属性
$request = $request->withAttribute('user', 'demo');
return $handler->handle($request);
}
}
注册这个类中间件时,如果用了容器,直接在pipeline.php里通过工厂解析并pipe。若手动注册,可在引导文件用new AuthMiddleware(['abc123'])后传入。注意中间件构造函数依赖应当来自配置,而非硬编码,否则测试时难以模拟。Mezzio的容器会自动注入validTokens这类参数,只要你在config/autoload/dependencies.php里声明好工厂。
闭包风格则更轻量,例如只想给响应加个自定义头:
<?php
$app->pipe(function (ServerRequestInterface $request, RequestHandlerInterface $handler) {
$response = $handler->handle($request);
return $response->withHeader('X-Powered-By', 'Mezzio');
});
这种写法在原型阶段很高效,但闭包无法被容器管理,也不能方便复用。当团队规模扩大,建议把稳定逻辑沉淀为类中间件,并以接口隔离。此外,Mezzio允许给pipe传路径前缀,比如$app->pipe('/api', $authMiddleware),这样只有匹配/api开头的请求才走鉴权,静态资源或健康检查发现可绕过,减少不必要开销。
路由层绑定处理器时,也可用中间件方式包裹。比如$app->route('/user', [AuthMiddleware::class, UserHandler::class]),数组形式表示先过鉴权再过业务。这种细粒度控制比全局管道更灵活,也避免了对健康检查的误伤。掌握这些注册手段,你就能把PSR-15中间件真正落成可维护的PHP应用骨架。
MezzioPSR-15php_middleware修改时间:2026-08-15 16:42:45