中间件

这里的中间件指的是"中间件模式",该功能属于 hyperf/http-server 组件内的一项主要功能,主要用于编织从 请求(Request)响应(Response) 的整个流程,该功能完成基于 PSR-15 实现。

原理

中间件主要用于编织从 请求(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/autoload/middlewares.php ,配置如下:

  1. <?php
  2. return [
  3. // http 对应 config/server.php 内每个 server 的 name 属性对应的值,该配置仅应用在该 Server 中
  4. 'http' => [
  5. // 数组内配置您的全局中间件,顺序根据该数组的顺序
  6. YourMiddleware::class
  7. ],
  8. ];

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

定义局部中间件

当我们有些中间件仅仅面向某些请求或控制器时,即可将其定义为局部中间件,可通过配置文件的方式定义或注解的方式。

通过配置文件定义

在使用配置文件定义路由时,推荐通过配置文件来定义对应的中间件,局部中间件的配置将在路由配置上完成。Hyperf\HttpServer\Router\Router 类的每个定义路由的方法的最后一个参数 $options 都将接收一个数组,可通过传递键值 middleware 及一个数组值来定义该路由的中间件,我们通过几个路由定义来演示一下:

  1. <?php
  2. use App\Middleware\FooMiddleware;
  3. use Hyperf\HttpServer\Router\Router;
  4. // 每个路由定义方法都可接收一个 $options 参数
  5. Router::get('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [ForMiddleware::class]]);
  6. Router::post('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [ForMiddleware::class]]);
  7. Router::put('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [ForMiddleware::class]]);
  8. Router::patch('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [ForMiddleware::class]]);
  9. Router::delete('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [ForMiddleware::class]]);
  10. Router::head('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [ForMiddleware::class]]);
  11. Router::addRoute(['GET', 'POST', 'HEAD'], '/index', [\App\Controller\IndexController::class, 'index'], ['middleware' => [ForMiddleware::class]]);
  12. // 该 Group 下的所有路由都将应用配置的中间件
  13. Router::addGroup(
  14. '/v2', function () {
  15. Router::get('/index', [\App\Controller\IndexController::class, 'index']);
  16. },
  17. ['middleware' => [ForMiddleware::class]]
  18. );

通过注解定义

在通过注解定义路由时,我们推荐通过注解的方式来定义中间件,对中间件的定义有两个注解,分别为:

  • @Middleware 注解为定义单个中间件时使用,在一个地方仅可定义一个该注解,不可重复定义
  • @Middlewares 注解为定义多个中间件时使用,在一个地方仅可定义一个该注解,然后通过在该注解内定义多个 @Middleware 注解实现多个中间件的定义

使用 @Middleware 注解时需 use Hyperf\HttpServer\Annotation\Middleware; 命名空间;
使用 @Middlewares 注解时需 use Hyperf\HttpServer\Annotation\Middlewares; 命名空间;

定义单个中间件:

  1. <?php
  2. use App\Middleware\FooMiddleware;
  3. use Hyperf\HttpServer\Annotation\AutoController;
  4. use Hyperf\HttpServer\Annotation\Middleware;
  5. /**
  6. * @AutoController()
  7. * @Middleware(FooMiddleware::class)
  8. */
  9. class IndexController
  10. {
  11. public function index()
  12. {
  13. return 'Hello Hyperf.';
  14. }
  15. }

定义多个中间件:

  1. <?php
  2. use App\Middleware\BarMiddleware;
  3. use App\Middleware\FooMiddleware;
  4. use Hyperf\HttpServer\Annotation\AutoController;
  5. use Hyperf\HttpServer\Annotation\Middleware;
  6. /**
  7. * @AutoController()
  8. * @Middlewares({
  9. * @Middleware(FooMiddleware::class),
  10. * @Middleware(BarMiddleware::class)
  11. * })
  12. */
  13. class IndexController
  14. {
  15. public function index()
  16. {
  17. return 'Hello Hyperf.';
  18. }
  19. }

定义方法级别的中间件

在通过配置文件的方式配置中间件时定义到方法级别上很简单,那么要通过注解的形式定义到方法级别呢?您只需将注解直接定义到方法上即可。方法级别上的中间件会优先于类级别的中间件,我们通过代码来举例一下:

  1. <?php
  2. use App\Middleware\BarMiddleware;
  3. use App\Middleware\FooMiddleware;
  4. use Hyperf\HttpServer\Annotation\AutoController;
  5. use Hyperf\HttpServer\Annotation\Middleware;
  6. use Hyperf\HttpServer\Annotation\Middlewares;
  7. /**
  8. * @AutoController()
  9. * @Middlewares({
  10. * @Middleware(FooMiddleware::class)
  11. * })
  12. */
  13. class IndexController
  14. {
  15. /**
  16. * @AutoController()
  17. * @Middlewares({
  18. * @Middleware(BarMiddleware::class)
  19. * })
  20. */
  21. public function index()
  22. {
  23. return 'Hello Hyperf.';
  24. }
  25. }

中间件的执行顺序为 BarMiddleware -> FooMiddleware

中间件的执行顺序

我们从上面可以了解到总共有 3 种级别的中间件,分别为 全局中间件类级别中间件方法级别中间件,如果都定义了这些中间件,执行顺序为:全局中间件 -> 方法级别中间件 -> 类级别中间件