Hyperf 安装,利用,

打印 上一主题 下一主题

主题 556|帖子 556|积分 1668

安装,

一般开发都是windows,所以用虚拟机或docker
利用

启动

  1. php bin/hyperf.php start
复制代码

假如出现端口被占用,下面的处理方法

  • 检察9501端口那个进程在占用
  1. netstat -anp|grep 9501
复制代码

2. kill掉
  1. kill 18
复制代码

  • 然后再启动即可
热更新

Watcher 组件除了办理上述启动问题,还提供了文件修改后立马重启的功能。
安装

  1. composer require hyperf/watcher --dev
复制代码
发布配置

  1. php bin/hyperf.php vendor:publish hyperf/watcher
复制代码
  发布配置后在目录config/autoload/下自动生成watcher.php文件
  

配置 默认值 备注
driverScanFileDriver默认定时扫描文件驱动binPHP_BINARY用于启动服务的脚本watch.dirapp, config监听目录watch.file.env监听文件watch.interval2000扫描隔断(毫秒)ext.php, .env监听目录下的文件扩展名 启动

hyperf框架可以利用hyperf/watcher举行热更新操纵,不消每次修改完代码都重启服务
注意:
利用php bin/hyperf.php server:watch
这个命令后,php bin/hyperf.php start 这个命令将废弃
  1. php bin/hyperf.php server:watch
复制代码
路由

配置文件路由

  1. <?php
  2. use Hyperf\HttpServer\Router\Router;
  3. // 此处代码示例为每个示例都提供了三种不同的绑定定义方式,实际配置时仅可采用一种且仅定义一次相同的路由
  4. // 设置一个 GET 请求的路由,绑定访问地址 '/get' 到 App\Controller\IndexController 的 get 方法
  5. Router::get('/get', 'App\Controller\IndexController::get');
  6. Router::get('/get', 'App\Controller\IndexController@get');
  7. Router::get('/get', [\App\Controller\IndexController::class, 'get']);
  8. // 设置一个 POST 请求的路由,绑定访问地址 '/post' 到 App\Controller\IndexController 的 post 方法
  9. Router::post('/post', 'App\Controller\IndexController::post');
  10. Router::post('/post', 'App\Controller\IndexController@post');
  11. Router::post('/post', [\App\Controller\IndexController::class, 'post']);
  12. // 设置一个允许 GET、POST 和 HEAD 请求的路由,绑定访问地址 '/multi' 到 App\Controller\IndexController 的 multi 方法
  13. Router::addRoute(['GET', 'POST', 'HEAD'], '/multi', 'App\Controller\IndexController::multi');
  14. Router::addRoute(['GET', 'POST', 'HEAD'], '/multi', 'App\Controller\IndexController@multi');
  15. Router::addRoute(['GET', 'POST', 'HEAD'], '/multi', [\App\Controller\IndexController::class, 'multi']);
复制代码
路由组

  1. Router::addGroup('/user',function (){
  2.     Router::get('/index', 'App\Controller\UserController::index');
  3.     Router::post('/create', 'App\Controller\UserController::createUser');
  4.     Router::put('/update', 'App\Controller\UserController::update');
  5.     Router::delete('/delete', 'App\Controller\UserController::delete');
  6. });
复制代码
必填参数

我们可以对 $uri 举行一些参数界说,通过 {} 来声明参数,如 /user/{id} 则声明了 id 值为一个必填参数。
可选参数

偶然间您大概会希望这个参数是可选的,您可以通过[]来声明中括号内的参数为一个可选参数,如 /user/[{id}]。
校验参数

您也可以利用正则表达式对参数举行校验,以下是一些例子
  1. use Hyperf\HttpServer\Router\Router;
  2. // 可以匹配 /user/42, 但不能匹配 /user/xyz
  3. Router::addRoute('GET', '/user/{id:\d+}', 'handler');
  4. // 可以匹配 /user/foobar, 但不能匹配 /user/foo/bar
  5. Router::addRoute('GET', '/user/{name}', 'handler');
  6. // 也可以匹配 /user/foo/bar as well
  7. Router::addRoute('GET', '/user/{name:.+}', 'handler');
  8. // 这个路由
  9. Router::addRoute('GET', '/user/{id:\d+}[/{name}]', 'handler');
  10. // 等同于以下的两个路由
  11. Router::addRoute('GET', '/user/{id:\d+}', 'handler');
  12. Router::addRoute('GET', '/user/{id:\d+}/{name}', 'handler');
  13. // 多个可选的嵌套也是允许的
  14. Router::addRoute('GET', '/user[/{id:\d+}[/{name}]]', 'handler');
  15. // 这是一条无效的路由, 因为可选部分只能出现在最后
  16. Router::addRoute('GET', '/user[/{id:\d+}]/{name}', 'handler');
复制代码
注解路由


例如:
  1. <?php
  2. /**
  3. * OrderController.php
  4. *
  5. * Created on Orders-11:19
  6. * Created by xxp 332410549@qq.com
  7. */
  8. namespace App\Controller;
  9. use Hyperf\HttpServer\Annotation\Controller;
  10. use Hyperf\HttpServer\Annotation\GetMapping;
  11. use Hyperf\HttpServer\Contract\RequestInterface;
  12. /**
  13. * @Controller(prefix="order")
  14. */
  15. class OrderController extends AbstractController
  16. {
  17.     /**
  18.      * @GetMapping(path="index")
  19.      */
  20.     public function index(RequestInterface $request)
  21.     {
  22.         return 'OrderController'.$request->input('id');
  23.     }
  24. }
复制代码
访问地点
  1. http://hyperf.demos.xp:9501/order/index
复制代码
HTTP 非常

在路由匹配不到路由时,如 路由找不到(404)、请求方法不答应(405) 等 HTTP 非常,Hyperf 会同一抛出一个 Hyperf\HttpMessage\Exception\HttpException 非常类的子类,
您需要通过 ExceptionHandler 机制来管理这些非常并做对应的响应处理,默认环境下可以直接利用组件提供的 Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler 来举行非常捕获处理,注意这个非常处理器需要您自行配置到 config/autoload/exceptions.php 配置文件中去,并保障多个非常处理器之间的序次链路是正确的。
当您需要对 路由找不到(404)、请求方法不答应(405) 等 HTTP 非常环境的响应举行自界说处理时,您可直接根据 HttpExceptionHandler 的代码实现您自己的非常处理器,并配置您自己的非常处理器。关于非常处理器的逻辑和利用说明,可具体查阅 非常处理
非常处理器

在 Hyperf 里,业务代码都运行在 Worker 进程 上,也就意味着一旦恣意一个请求的业务存在没有捕获处理的非常的话,都会导致对应的 Worker 进程 被停止退出,这对服务而言也是不能接受的,捕获非常并输出公道的报错内容给客户端也是更加友好的。
我们可以通过对各个 server 界说不同的 非常处理器(ExceptionHandler),一旦业务流程存在没有捕获的非常,都会被通报到已注册的 非常处理器(ExceptionHandler) 去处理。
自界说一个非常处理


1. 通过配置文件注册非常处理器

config/autoload/exceptions.php 文件
  1. <?php
  2. // config/autoload/exceptions.php
  3. return [
  4.     'handler' => [
  5.         'http' => [
  6.             Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler::class,
  7.             App\Exception\Handler\AppExceptionHandler::class,
  8.             App\Exception\Handler\FooExceptionHandler::class,
  9.         ],
  10.     ],
  11. ];
复制代码
2. 界说非常处理器

app/Exception/Handler/FooExceptionHandler.php
  1. <?php
  2. /**
  3. * FooExceptionHandler.php
  4. *
  5. * Created on ExceptionHandler -13:35
  6. * Created by xxp 332410549@qq.com
  7. */
  8. namespace App\Exception\Handler;
  9. use App\Exception\FooException;
  10. use Hyperf\ExceptionHandler\ExceptionHandler;
  11. use Hyperf\HttpMessage\Stream\SwooleStream;
  12. use Psr\Http\Message\ResponseInterface;
  13. use Throwable;
  14. class FooExceptionHandler extends ExceptionHandler
  15. {
  16.     /**
  17.      * @inheritDoc
  18.      */
  19.     public function handle(Throwable $throwable, ResponseInterface $response)
  20.     {
  21.         // 判断被捕获到的异常是希望被捕获的异常
  22.         if ($throwable instanceof FooException) {
  23.             // 格式化输出
  24.             $data = json_encode([
  25.                 'code' => $throwable->getCode(),
  26.                 'message' => $throwable->getMessage(),
  27.             ], JSON_UNESCAPED_UNICODE);
  28.             // 阻止异常冒泡
  29.             $this->stopPropagation();
  30.             return $response->withStatus(500)->withBody(new SwooleStream($data));
  31.         }
  32.         // 交给下一个异常处理器
  33.         return $response;
  34.     }
  35.     /**
  36.      * @inheritDoc
  37.      */
  38.     public function isValid(Throwable $throwable): bool
  39.     {
  40.        return true;
  41.     }
  42. }
复制代码
3. 界说非常类

app/Exception/FooException.php
  1. <?php
  2. /**
  3. * FooException.php
  4. *
  5. * Created on FooException-13:40
  6. * Created by xxp 332410549@qq.com
  7. */
  8. namespace App\Exception;
  9. use Hyperf\Server\Exception\ServerException;
  10. class FooException extends ServerException
  11. {
  12. }
复制代码
4. 触发非常

  1. <?php
  2. /**
  3. * OrderController.php
  4. *
  5. * Created on Orders-11:19
  6. * Created by xxp 332410549@qq.com
  7. */
  8. namespace App\Controller;
  9. use App\Exception\FooException;
  10. use Hyperf\HttpServer\Annotation\Controller;
  11. use Hyperf\HttpServer\Annotation\GetMapping;
  12. use Hyperf\HttpServer\Contract\RequestInterface;
  13. /**
  14. * @Controller(prefix="order")
  15. */
  16. class OrderController extends AbstractController
  17. {
  18.     /**
  19.      * @GetMapping(path="index")
  20.      */
  21.     public function index(RequestInterface $request)
  22.     {
  23.         try {
  24.             $data = [
  25.                 'code' => 0,
  26.                 'msg' => '获取成功',
  27.                 'data' => [
  28.                     'orders' => '订单列表'
  29.                 ]
  30.             ];
  31.             if (1) {   // 如果没有数据,返回空数组
  32.               throw new FooException('自定义异常');
  33.             }
  34.             return $this->response->json($data);
  35.         } catch (\Exception $e) {
  36.             return $this->response->json(['code' => 1,'msg' => $e->getMessage()]);
  37.         }
  38.     }
  39. }
复制代码
检察办理


总结:
在上面这个例子,我们先假设 FooException 是存在的一个非常,以及假设已经完成了该处理器的配置,那么当业务抛出一个没有被捕获处理的非常时,就会根据配置的序次依次通报,整一个处理流程可以明白为一个管道,若前一个非常处理器调用 $this->stopPropagation() 则不再往后通报,若最后一个配置的非常处理器仍不对该非常举行捕获处理,那么就会交由 Hyperf 的默认非常处理器处理了。
Error 监听器

框架提供了 error_reporting() 错误级别的监听器 Hyperf\ExceptionHandler\Listener\ErrorExceptionHandler。
配置

在 config/autoload/listeners.php 中添加监听器
  1. <?php
  2. return [
  3.     \Hyperf\ExceptionHandler\Listener\ErrorExceptionHandler::class
  4. ];
复制代码
抓取错误

则当出现类似以下的代码时会抛出 \ErrorException 非常
  1.     public function index(RequestInterface $request)
  2.     {
  3.         try {
  4.             $a = [];
  5.             ($a[1]);
  6.             return $this->response->json($data);
  7.         } catch (\Throwable $e) {
  8.             return $this->response->json(['code' => 1,'msg' => $e->getMessage() ."\n num:". $e->getLine()]);
  9.         }
  10.     }
复制代码
结果


中间件

原理图

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

图中的序次为按照 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/autoload/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' => [FooMiddleware::class]]);
  6. Router::post('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [FooMiddleware::class]]);
  7. Router::put('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [FooMiddleware::class]]);
  8. Router::patch('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [FooMiddleware::class]]);
  9. Router::delete('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [FooMiddleware::class]]);
  10. Router::head('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [FooMiddleware::class]]);
  11. Router::addRoute(['GET', 'POST', 'HEAD'], '/index', [\App\Controller\IndexController::class, 'index'], ['middleware' => [FooMiddleware::class]]);
  12. // 该 Group 下的所有路由都将应用配置的中间件
  13. Router::addGroup(
  14.     '/v2', function () {
  15.         Router::get('/index', [\App\Controller\IndexController::class, 'index']);
  16.     },
  17.     ['middleware' => [FooMiddleware::class]]
  18. );
复制代码
通过注解界说

在通过注解界说路由时,您仅可通过注解的方式来界说中间件,对中间件的界说有两个注解,分别为:
#[Middleware] 注解为界说单个中间件时利用,在一个地方仅可界说一个该注解,不可重复界说
#[Middlewares] 注解为界说多个中间件时利用,在一个地方仅可界说一个该注解,然后通过在该注解内界说多个 #[Middleware] 注解实现多个中间件的界说
利用 #[Middleware] 注解时需 use Hyperf\HttpServer\Annotation\Middleware; 命名空间;
利用 #[Middlewares] 注解时需 use Hyperf\HttpServer\Annotation\Middlewares; 命名空间;
注意:必须共同 #[AutoController] 大概 #[Controller] 利用
界说单个中间件:

  1. <?php
  2. namespace App\Controller;
  3. use App\Middleware\FooMiddleware;
  4. use Hyperf\HttpServer\Annotation\AutoController;
  5. use Hyperf\HttpServer\Annotation\Middleware;
  6. #[AutoController]
  7. #[Middleware(FooMiddleware::class)]
  8. class IndexController
  9. {
  10.     public function index()
  11.     {
  12.         return 'Hello Hyperf.';
  13.     }
  14. }
复制代码
通过 #[Middlewares] 注解界说多个中间件:

  1. <?php
  2. namespace App\Controller;
  3. use App\Middleware\BarMiddleware;
  4. use App\Middleware\FooMiddleware;
  5. use Hyperf\HttpServer\Annotation\AutoController;
  6. use Hyperf\HttpServer\Annotation\Middleware;
  7. use Hyperf\HttpServer\Annotation\Middlewares;
  8. #[AutoController]
  9. #[Middlewares([FooMiddleware::class, BarMiddleware::class])]
  10. class IndexController
  11. {
  12.     public function index()
  13.     {
  14.         return 'Hello Hyperf.';
  15.     }
  16. }
复制代码
界说方法级别的中间件

在通过配置文件的方式配置中间件时界说到方法级别上很简朴,那么要通过注解的情势界说到方法级别呢?您只需将注解直接界说到方法上即可。
类级别上的中间件会优先于方法级别的中间件,我们通过代码来举例一下:
  1. <?php
  2. namespace App\Controller;
  3. use App\Middleware\BarMiddleware;
  4. use App\Middleware\FooMiddleware;
  5. use Hyperf\HttpServer\Annotation\AutoController;
  6. use Hyperf\HttpServer\Annotation\Middleware;
  7. use Hyperf\HttpServer\Annotation\Middlewares;
  8. #[AutoController]
  9. #[Middlewares([FooMiddleware::class])]
  10. class IndexController
  11. {
  12.     #[Middleware(BarMiddleware::class)]
  13.     public function index()
  14.     {
  15.         return 'Hello Hyperf.';
  16.     }
  17. }
复制代码
中间件相干的代码
生成中间件
  1. php ./bin/hyperf.php gen:middleware Auth/FooMiddleware
复制代码
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Middleware\Auth;
  4. use Hyperf\HttpServer\Contract\RequestInterface;
  5. use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
  6. use Psr\Container\ContainerInterface;
  7. use Psr\Http\Message\ResponseInterface;
  8. use Psr\Http\Message\ServerRequestInterface;
  9. use Psr\Http\Server\MiddlewareInterface;
  10. use Psr\Http\Server\RequestHandlerInterface;
  11. class FooMiddleware implements MiddlewareInterface
  12. {
  13.     protected ContainerInterface $container;
  14.     protected RequestInterface $request;
  15.     protected HttpResponse $response;
  16.     public function __construct(ContainerInterface $container, HttpResponse $response, RequestInterface $request)
  17.     {
  18.         $this->container = $container;
  19.         $this->response = $response;
  20.         $this->request = $request;
  21.     }
  22.     public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
  23.     {
  24.         // 根据具体业务判断逻辑走向,这里假设用户携带的token有效
  25.         $isValidToken = true;
  26.         if ($isValidToken) {
  27.             return $handler->handle($request);
  28.         }
  29.         return $this->response->json(
  30.             [
  31.                 'code' => -1,
  32.                 'data' => [
  33.                     'error' => '中间件验证token无效,阻止继续向下执行',
  34.                 ],
  35.             ]
  36.         );
  37.     }
  38. }
复制代码
中间件的执行序次为 FooMiddleware -> BarMiddleware。
中间件的执行序次

我们从上面可以相识到总共有 3 种级别的中间件,分别为 全局中间件、类级别中间件、方法级别中间件,假如都界说了这些中间件,执行序次为:全局中间件 -> 类级别中间件 -> 方法级别中间件。
在>=3.0.34的版本中,新增了优先级的配置,可以在配置方法、路由中间件的时间改变中间件的执行序次,优先级越高,执行序次越靠前。
// 全局中间件配置文件 middleware.php
  1. return [
  2.     'http' => [
  3.         YourMiddleware::class,
  4.         YourMiddlewareB::class => 3,
  5.     ],
  6. ];
  7. Copy to clipboardErrorCopied
  8. // 路由中间件配置
  9. Router::addGroup(
  10.     '/v2', function () {
  11.         Router::get('/index', [\App\Controller\IndexController::class, 'index']);
  12.     },
  13.     [
  14.         'middleware' => [
  15.             FooMiddleware::class,
  16.             FooMiddlewareB::class => 3,
  17.         ]
  18.     ]
  19. );
复制代码
// 注解中间件配置
  1. #[AutoController]
  2. #[Middleware(FooMiddleware::class)]
  3. #[Middleware(FooMiddlewareB::class, 3)]
  4. #[Middlewares([FooMiddlewareC::class => 1, BarMiddlewareD::class => 4])]
  5. class IndexController
  6. {
  7.    
  8. }
复制代码
全局更改请求和响应对象

首先,在协程上下文内是有存储最原始的 PSR-7 请求对象 和 响应对象 的,且根据 PSR-7 对相干对象所要求的 不可变性(immutable),也就意味着我们在调用 $response = $response->with***() 所调用得到的 $response,并非为改写原对象,而是一个 Clone 出来的新对象,也就意味着我们储存在协程上下文内的 请求对象 和 响应对象 是不会改变的,那么当我们在中间件内的某些逻辑改变了 请求对象 或 响应对象,而且我们希望对后续的 非通报性的 代码再获取改变后的 请求对象 或 响应对象,那么我们便可以在改变对象后,将新的对象设置到上下文中,如代码所示:
  1. use Psr\Http\Message\ResponseInterface;
  2. use Psr\Http\Message\ServerRequestInterface;
  3. // $request 和 $response 为修改后的对象
  4. $request = \Hyperf\Context\Context::set(ServerRequestInterface::class, $request);
  5. $response = \Hyperf\Context\Context::set(ResponseInterface::class, $response);
复制代码
自界说 CoreMiddleWare 的举动

默认环境下,Hyperf 在处理路由找不到或 HTTP 方法不答应时,即 HTTP 状态码为 404、405 的时间,是由 CoreMiddleware 直接处理并返回对应的响应对象的,得益于 Hyperf 依靠注入的设计,您可以通过更换对象的方式来把 CoreMiddleware 指向由您自己实现的 CoreMiddleware 去。
比如我们希望界说一个 App\Middleware\CoreMiddleware 类来重写默认的举动,我们可以先界说一个 App\Middleware\CoreMiddleware 类如下,这里我们仅以 HTTP Server 为例,其它 Server 也可采用同样的做法来达到同样的目的。
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Middleware;
  4. use Hyperf\Contract\Arrayable;
  5. use Hyperf\HttpMessage\Stream\SwooleStream;
  6. use Psr\Http\Message\ResponseInterface;
  7. use Psr\Http\Message\ServerRequestInterface;
  8. class CoreMiddleware extends \Hyperf\HttpServer\CoreMiddleware
  9. {
  10.     /**
  11.      * Handle the response when cannot found any routes.
  12.      *
  13.      * @return array|Arrayable|mixed|ResponseInterface|string
  14.      */
  15.     protected function handleNotFound(ServerRequestInterface $request)
  16.     {
  17.         // 重写路由找不到的处理逻辑
  18.         return $this->response()->withStatus(404);
  19.     }
  20.     /**
  21.      * Handle the response when the routes found but doesn't match any available methods.
  22.      *
  23.      * @return array|Arrayable|mixed|ResponseInterface|string
  24.      */
  25.     protected function handleMethodNotAllowed(array $methods, ServerRequestInterface $request)
  26.     {
  27.         // 重写 HTTP 方法不允许的处理逻辑
  28.         return $this->response()->withStatus(405);
  29.     }
  30. }
复制代码
然后再在 config/autoload/dependencies.php 界说对象关系重写 CoreMiddleware 对象:
  1. <?php
  2. return [
  3.     Hyperf\HttpServer\CoreMiddleware::class => App\Middleware\CoreMiddleware::class,
  4. ];
复制代码
这里直接重写 CoreMiddleware 的做法需要在 1.1.0+ 版本上才有效,1.0.x 版本仍需要你再将 CoreMiddleware 的上层调用通过 DI 举行重写,然后更换 CoreMiddleware 的传值为您界说的中间件类。
常用中间件

跨域中间件
假如您需要在框架中办理跨域,则可以按照您的需求实现以下中间件
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Middleware;
  4. use Hyperf\Context\Context;
  5. use Psr\Http\Message\ResponseInterface;
  6. use Psr\Http\Message\ServerRequestInterface;
  7. use Psr\Http\Server\MiddlewareInterface;
  8. use Psr\Http\Server\RequestHandlerInterface;
  9. class CorsMiddleware implements MiddlewareInterface
  10. {
  11.     public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
  12.     {
  13.         $response = Context::get(ResponseInterface::class);
  14.         $response = $response->withHeader('Access-Control-Allow-Origin', '*')
  15.             ->withHeader('Access-Control-Allow-Credentials', 'true')
  16.             // Headers 可以根据实际情况进行改写。
  17.             ->withHeader('Access-Control-Allow-Headers', 'DNT,Keep-Alive,User-Agent,Cache-Control,Content-Type,Authorization');
  18.         Context::set(ResponseInterface::class, $response);
  19.         if ($request->getMethod() == 'OPTIONS') {
  20.             return $response;
  21.         }
  22.         return $handler->handle($request);
  23.     }
  24. }
复制代码
实际上,跨域配置也可以直接挂在 Nginx 上。
  1. location / {
  2.     add_header Access-Control-Allow-Origin *;
  3.     add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
  4.     add_header Access-Control-Allow-Headers 'DNT,Keep-Alive,User-Agent,Cache-Control,Content-Type,Authorization';
  5.     if ($request_method = 'OPTIONS') {
  6.         return 204;
  7.     }
  8. }
复制代码
后置中间件
通常环境下,我们都是最后执行
return                                    h                         a                         n                         d                         l                         e                         r                         −                         >                         h                         a                         n                         d                         l                         e                         (                              handler->handle(                  handler−>handle(request);
Copy to clipboardErrorCopied
所以,相称于是前置中间件,假如想要让中间件逻辑后置,其实只需要更换一下执行序次即可。
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Middleware;
  4. use Hyperf\HttpServer\Contract\RequestInterface;
  5. use Psr\Container\ContainerInterface;
  6. use Psr\Http\Message\ResponseInterface;
  7. use Psr\Http\Message\ServerRequestInterface;
  8. use Psr\Http\Server\MiddlewareInterface;
  9. use Psr\Http\Server\RequestHandlerInterface;
  10. class OpenApiMiddleware implements MiddlewareInterface
  11. {
  12.     public function __construct(protected ContainerInterface $container)
  13.     {
  14.     }
  15.     public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
  16.     {
  17.         // TODO: 前置操作
  18.         try{
  19.             $result = $handler->handle($request);
  20.         } finally {
  21.             // TODO: 后置操作
  22.         }
  23.         return $result;
  24.     }
  25. }
复制代码
实践


中间件文件

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Middleware\Auth;
  4. use Psr\Container\ContainerInterface;
  5. use Psr\Http\Message\ResponseInterface;
  6. use Psr\Http\Server\MiddlewareInterface;
  7. use Psr\Http\Message\ServerRequestInterface;
  8. use Psr\Http\Server\RequestHandlerInterface;
  9. use Hyperf\HttpServer\Contract\RequestInterface;
  10. use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
  11. class FooMiddleware implements MiddlewareInterface
  12. {
  13.     /**
  14.      * @var ContainerInterface
  15.      */
  16.     protected $container;
  17.     /**
  18.      * @var RequestInterface
  19.      */
  20.     protected $request;
  21.     /**
  22.      * @var HttpResponse
  23.      */
  24.     protected $response;
  25.     public function __construct(ContainerInterface $container, HttpResponse $response, RequestInterface $request)
  26.     {
  27.         $this->container = $container;
  28.         $this->response = $response;
  29.         $this->request = $request;
  30.     }
  31.     public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
  32.     {
  33.         $isValidToken = true;
  34.         if ($isValidToken) {
  35.             return $handler->handle($request);
  36.         }
  37.         return $this->response->json(
  38.             [
  39.                 'code' => -1,
  40.                 'data' => [
  41.                     'error' => '中间件验证token无效,阻止继续向下执行 ',
  42.                 ],
  43.             ]
  44.         );
  45.     }
  46. }
复制代码
$isValidToken 根据具体业务来判断
假如为真,则放行
假如为假,则阻断
中间件调用

  1. <?php
  2. /**
  3. * Message.php
  4. *
  5. * Created on Message-15:28
  6. * Created by xxp 332410549@qq.com
  7. */
  8. namespace App\Controller;
  9. use Hyperf\HttpServer\Annotation\AutoController;
  10. use App\Controller\AbstractController;
  11. use Hyperf\HttpServer\Annotation\Middleware;
  12. use App\Middleware\Auth\FooMiddleware;
  13. /**
  14. * @AutoController()
  15. * @Middleware(FooMiddleware::class)
  16. */
  17. class MessageController extends AbstractController
  18. {
  19.     public function index()
  20.     {
  21.         return 'message';
  22.     }
  23. }
复制代码
结果



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

熊熊出没

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表