You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Aura Router实现路由专属中间件?当前写法报错

解决Aura Router路由专属中间件报错“Invalid request handler: array”的问题

嘿,我明白你碰到的困扰了——想给特定路由加专属中间件,结果用数组把中间件和控制器方法绑在一起时,触发了Invalid request handler: array错误。这是因为Aura Router和Request Handler的默认逻辑里,路由的handler参数只接受可调用字符串(比如控制器方法路径)、闭包,或是能被容器解析的服务标识,并不直接支持数组形式的「中间件+handler」组合。

下面给你两种可行的解决方案,都能实现路由级专属中间件的效果:

方案1:利用路由选项存储中间件,动态注入处理链

这种方法的核心是把路由专属中间件存在路由的options里,在Dispatcher流程中先匹配路由,再根据路由信息动态把中间件加入处理链。

步骤1:定义路由时添加中间件选项

$routerContainer = new RouterContainer();
$map = $routerContainer->getMap();

// 给目标路由绑定专属中间件到options
$map->get('index', '/', 'App\Http\Controllers\HomeController::index')
    ->setOptions([
        'middleware' => [new SampleRouteMiddleware()]
    ]);

// 其他路由正常定义即可
$map->get('about', '/about', 'App\Http\Controllers\AboutController::index');

步骤2:创建路由中间件处理类

这个类会在路由匹配完成后,检查当前路由是否有专属中间件,有则把它们插入到请求处理链中:

use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Http\Message\ResponseInterface;
use Zend\Stratigility\Middleware\RequestHandlerStack;

class RouteMiddlewareHandler implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        // 从请求属性中获取Aura Router匹配到的路由对象
        $route = $request->getAttribute('route');
        
        if ($route && isset($route->options['middleware'])) {
            // 把路由专属中间件和原handler组成新的处理栈
            $middlewareStack = $route->options['middleware'];
            array_push($middlewareStack, $handler);
            $newHandler = new RequestHandlerStack($middlewareStack);
            
            return $newHandler->handle($request);
        }
        
        // 无路由中间件则直接执行原流程
        return $handler->handle($request);
    }
}

步骤3:调整Dispatcher的中间件顺序

关键:必须把路由匹配中间件放在路由中间件处理器之前,这样才能先拿到路由信息:

$request = ServerRequestFactory::fromGlobals($_SERVER, $_GET, $_POST, $_COOKIE, $_FILES);
$requestContainer = new RequestHandlerContainer();

$dispatcher = new Dispatcher([
    new SampleAppMiddleware(), // 全局应用中间件(所有路由生效)
    new AuraRouter($routerContainer), // 先完成路由匹配
    new RouteMiddlewareHandler(), // 处理当前路由的专属中间件
    new RequestHandler($requestContainer), // 最终执行控制器方法
]);

$response = $dispatcher->dispatch($request);

方案2:通过RequestHandler容器注册带中间件包裹的处理程序

这种方法是提前把「中间件+控制器方法」的组合注册到容器里,路由直接指向这个注册好的服务标识。

步骤1:在容器中注册带中间件的处理服务

$requestContainer = new RequestHandlerContainer();

// 注册被SampleRouteMiddleware包裹的首页控制器处理程序
$requestContainer->set('home.index', function () {
    $controller = new App\Http\Controllers\HomeController();
    // 把中间件和控制器方法组成处理栈
    return new RequestHandlerStack([
        new SampleRouteMiddleware(),
        fn(ServerRequestInterface $req) => $controller->index($req)
    ]);
});

步骤2:路由指向容器中的服务标识

$routerContainer = new RouterContainer();
$map = $routerContainer->getMap();

// 路由的handler直接使用容器中注册的服务名
$map->get('index', '/', 'home.index');

步骤3:正常配置Dispatcher

$request = ServerRequestFactory::fromGlobals($_SERVER, $_GET, $_POST, $_COOKIE, $_FILES);

$dispatcher = new Dispatcher([
    new SampleAppMiddleware(),
    new AuraRouter($routerContainer),
    new RequestHandler($requestContainer),
]);

$response = $dispatcher->dispatch($request);

两种方案各有优势:方案1适合给多个路由批量配置中间件的场景,方案2则更灵活,适合对单个路由做精细的处理链定制。

内容的提问来源于stack exchange,提问作者bmatovu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:15:57