首页 文章

CakePHP 3.6:路由和中间件

提问于
浏览
1

我有一个创建图像缩略图的cakephp plugin .
目前,缩略图是由控制器的操作"served",该控制器将文件作为响应返回(here) .

这是路线:

Router::plugin(THUMBER, ['path' => '/thumb'], function (RouteBuilder $routes) {
    $routes->get('/:basename', ['controller' => 'Thumbs', 'action' => 'thumb'], 'thumb')
        ->setPatterns(['basename' => '[\w\d=]+'])
        ->setPass(['basename']);
});

所以url是这些(缩略图基名被编码):

/thumb/ZDc1NTYyMGY1N2VmMzRiNTQyZjE0NTY2Mjk0YWQ2NTFfNGIyYTBkMjVhMTdjZTdjN2E4MjVjY2M1YWU1ODNhMzcuZ2lm

现在我正在尝试用中间件替换控制器 .
这很简单,因为基本上它会像 AssetMiddleware 一样工作, __invoke() 方法几乎就像旧的操作方法:

class ThumbnailMiddleware
{
    use ThumbsPathTrait;

    public function __invoke($request, $response, $next)
    {
        if ($request->getParam('_name') !== 'thumb' || !$request->getParam('basename')) {
            return $next($request, $response);
        }

        $file = $this->getPath(base64_decode($request->getParam('basename')));

        if (!is_readable($file)) {
            throw new ThumbNotFoundException(__d('thumber', 'File `{0}` doesn\'t exist', $file));
        }

        $response = $response->withModified(filemtime($file));

        if ($response->checkNotModified($request)) {
            return $response;
        }

        return $response->withFile($file)->withType(mime_content_type($file));
    }
}

这非常有效 .
问题是它现在可以正常工作,因为这个中间件采用了控制器的路由并且不需要通过控制器就可以进行请求(参见 __invoke() 方法的前三行) .

现在我想重写该路由并从控制器解开它,我应该完全从插件中消除它 .

显然它的效果很好(第二个参数是 null ):

$routes->get('/:basename', null, 'thumb')
    ->setPatterns(['basename' => '[\w\d=]+'])
    ->setPass(['basename']);

或者我可以调用 RouteBuilder::fallback() 方法并分析请求的URL(因为它发生在 AssetMiddleware ) .

但我想知道是否有办法将路由仅链接到中间件并明确地用于中间件 . 或者,如果没有,最好的方法是什么 . 我知道我可以申请"middleware to specific routing scopes"(cookbook),所以我想知道这是否是正确的公式:

Router::plugin(THUMBER, ['path' => '/thumb'], function (RouteBuilder $routes) {
    $routes->registerMiddleware('thumbnail', new ThumbnailMiddleware);
    $routes->applyMiddleware('thumbnail');
    $routes->get('/:basename', null, 'thumb')
        ->setPatterns(['basename' => '[\w\d=]+'])
        ->setPass(['basename']);
});

1 回答

  • 2

    好吧,你不需要将任何默认值传递给一个路由,所以从这个角度来看它是一个控制器的"bound" . 如果您的中间件不会拦截请求,那么事情最终会被抛出 MissingControllerException ,因为调度程序将获得 null 作为控制器名称 . 由此产生的错误消息可能会有点误导,因为不会包含控制器名称 .

    你在那里做的将导致你的中间件应用于 /thumb 范围内的所有路由,所以如果有任何其他路由,那么你的中间件将需要根据参数检查 . 您可以通过将中间件应用于该特定路由而不是路由构建器来进一步限制事物:

    // $routes->applyMiddleware('thumbnail'); // don't do that
    $routes
        ->get('/:basename', null, 'thumb')
        ->setPatterns(['basename' => '[\w\d=]+'])
        ->setPass(['basename'])
        ->setMiddlware(['thumbnail']); // do this instead
    

    这样,您的中间件只会针对该特定路由调用 .

相关问题