轉(zhuǎn)載自如初博客:https://www.ziruchu.com/art/620
中間件原理
中間件的本質(zhì)是一個(gè) 洋蔥模型 。主要用于從 請(qǐng)求(Request) 到 響應(yīng)(Response) 的整個(gè)流程,使數(shù)組的流動(dòng)按照我們遇定的方式進(jìn)行。
圖中的順序?yàn)榘凑?Middleware 1 -> Middleware 2 -> Middleware 3 的順序組織著,我們可以注意到當(dāng)中間的橫線(xiàn)穿過(guò) 內(nèi)核 即 Middleware 3 后,又回到了 Middleware 2,為一個(gè)嵌套模型,那么實(shí)際的順序其實(shí)就是: Request -> Middleware 1 -> Middleware 2 -> Middleware 3 -> Middleware 2 -> Middleware 1 -> Response
重點(diǎn)放在 核心 即 Middleware 3,它是洋蔥的分界點(diǎn),分界點(diǎn)前面的部分其實(shí)都是基于 請(qǐng)求(Request) 進(jìn)行處理,而經(jīng)過(guò)了分界點(diǎn)時(shí),內(nèi)核 就產(chǎn)出了 響應(yīng)(Response) 對(duì)象,也是 內(nèi)核 的主要代碼目標(biāo),在之后便是對(duì) 響應(yīng)(Response) 進(jìn)行處理了,內(nèi)核 通常是由框架負(fù)責(zé)實(shí)現(xiàn)的,而其它的就由您來(lái)編排了。
從這個(gè)過(guò)程來(lái)看,其實(shí)有點(diǎn)像冒泡,把它當(dāng)作冒泡來(lái)理解可能還簡(jiǎn)單些。
中間件類(lèi)型
Hyperf 中,有全局中間件、局部中間件、方法級(jí)別的中間件。如果都定義了這些中間件,執(zhí)行順序?yàn)椋喝种虚g件 -> 類(lèi)級(jí)別中間件 -> 方法級(jí)別中間件。
全局中間件的使用
第一步:創(chuàng)建一個(gè)全局中間件
<?php
// App\Middleware\Api\ApiMiddleware.php
namespace App\Middleware\Api;
use PhpParser\Node\Stmt\Return_;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Hyperf\HttpServer\Contract\RequestInterface;
class ApiMiddleware implements MiddlewareInterface
{
public function __construct(
protected ContainerInterface $container,
protected \Hyperf\HttpServer\Contract\ResponseInterface $response,
protected RequestInterface $request
)
{
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
echo '全局中間間' . PHP_EOL;
// 業(yè)務(wù)邏輯處理
// $response = $handler->handle($request);
// 中間位置也可以處理
// return $response
return $handler->handle($request);
}
}
第二步:注冊(cè)全局中間件
<?php
// config/autoload/middlewares.php
declare(strict_types=1);
return [
'http' => [
\App\Middleware\Api\ApiMiddleware::class
],
];
這樣,中間件就定義完成了,
局部中間件的使用
方式一:路由中使用中間件
第一步:創(chuàng)建一個(gè)控制器
<?php
// App\Controller\Test\TestController.php
namespace App\Controller\Test;
class TestController
{
public function index()
{
echo 'Test 控制器' . PHP_EOL;
return 'test';
}
}
第二步:定義路由
Router::get('/test', [\App\Controller\Test\TestController::class, 'index'], ['middleware'=>[\App\Middleware\Api\RouterMiddleware::class]]);
方式二:通過(guò)注解使用中間件
<?php
// App\Controller\Test\PostController.php
namespace App\Controller\Test;
use App\Middleware\Api\PostMiddleware;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Annotation\Middleware;
#[AutoController]
#[Middleware(PostMiddleware::class)]
class PostController
{
public function index()
{
echo 'Post 控制器' . PHP_EOL;
return 'post index';
}
}
方式三:通過(guò)注解方式定義方法界別的中間件
<?php
// App\Controller\Test\VideoController.php
namespace App\Controller\Test;
use App\Middleware\Api\VideoMiddleware;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Annotation\Middleware;
#[AutoController]
class VideoController
{
#[Middleware(VideoMiddleware::class)]
public function index()
{
echo 'Video 控制器' . PHP_EOL;
return 'Video 控制器';
}
public function show()
{
return 'show';
}
}