# 中间件

这里的中间件指的是 "中间件模式",主要用于编织从 请求(Request)响应(Response) 的整个流程。

# 原理

中间件主要用于编织从 请求(Request)响应(Response) 的整个流程,通过对多个中间件的组织,使数据的流动按我们预定的方式进行,中间件的本质是一个 洋葱模型,我们通过一个图来解释它:

middleware

图中的顺序为按照 Middleware 1 -> Middleware 2 -> Middleware 3 的顺序组织着,我们可以注意到当中间的横线穿过 内核Middleware 3 后,又回到了 Middleware 2,为一个嵌套模型,那么实际的顺序其实就是:
Request -> Middleware 1 -> Middleware 2 -> Middleware 3 -> Middleware 2 -> Middleware 1 -> Response
重点放在 核心Middleware 3,它是洋葱的分界点,分界点前面的部分其实都是基于 请求(Request) 进行处理,而经过了分界点时,内核 就产出了 响应(Response) 对象,也是 内核 的主要代码目标,在之后便是对 响应(Response) 进行处理了,内核 通常是由框架负责实现的,而其它的就由您来编排了。

# 定义全局中间件

全局中间件只可通过配置文件的方式来配置,配置文件位于 config/middleware.config.php ,配置如下:

<?php

declare(strict_types=1);

use app\middleware\DuplicateRequestMiddleware;
use app\middleware\ValidateMiddleware;

return [
    DuplicateRequestMiddleware::class,
    ValidateMiddleware::class
];

只需将您的全局中间件配置在该文件上,即该 Server 下的所有请求都会应用配置的全局中间件。

全局验证器中间件的实现:

<?php

namespace app\middleware;

use herosphp\core\HttpRequest;
use herosphp\core\MiddlewareInterface;
use herosphp\plugin\validate\Valid;
use herosphp\plugin\validate\Validate;
use herosphp\plugin\validate\ValidateException;
use herosphp\WebApp;

class ValidateMiddleware implements MiddlewareInterface
{
    /**
     * @throws \ReflectionException
     */
    public function process(HttpRequest $request, callable $handler)
    {
        $reflectionMethod = new \ReflectionMethod(WebApp::$_targetController, WebApp::$_targetMethod);
        $reflectionAttributes = $reflectionMethod->getAttributes(Valid::class);
        if ($reflectionAttributes) {
            foreach ($reflectionAttributes as $validAttribute) {
                /** @var Valid $methodValidInstance */
                $methodValidInstance = $validAttribute->newInstance();
                $methodVInstance = new ($methodValidInstance->class);
                if (!$methodVInstance instanceof Validate) {
                    throw new ValidateException("{$methodVInstance->class} must extend \\herosphp\\plugin\\validate\Validate");
                }
                $methodVInstance->scene($methodValidInstance->scene)->check([...$request->get(), ...$request->post()]);
            }
        }
        return $handler($request);
    }
}

# 定义局部中间件

当我们有些中间件仅仅面向某些请求或控制器时,即可将其定义为局部中间件。

在需要特定Controller中,重写public array $middlewares = [];属性。

比如,我们需要对一些路由需要进行授权才能访问。

# 1. 新建一个 AuthenticationController

<?php
declare(strict_types=1);

namespace app\modules\admin\action\uc;

use app\modules\admin\middlewares\AuthenticationMiddleware;
use app\modules\admin\middlewares\OperateLogMiddleware;
use app\modules\admin\model\LoginAdmin;
use app\modules\admin\utils\LoginToSession;
use herosphp\core\BaseController;
use herosphp\WebApp;

// uc
class AbAuthenticationController extends BaseController
{
    public array $middlewares = [
        AuthenticationMiddleware::class // 认证 and 授权验证
    ];

    protected LoginAdmin $loginAdmin;

    /**
     * @throws \ReflectionException
     */
    public function __init()
    {
        parent::__init();
        $this->loginAdmin = LoginToSession::getLoginAdmin(WebApp::$_request);
    }
}

# 2. 所有需要登录的Controller 都可以继承该控制器,即可实现部分路由需要授权认证。

上次更新: 10/27/2022, 11:18:25 AM