Hyperf 安装,使用,

news2024/9/22 17:20:15

安装,

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

使用

启动

 php bin/hyperf.php start

在这里插入图片描述

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

  1. 查看9501端口那个进程在占用
 netstat -anp|grep 9501

在这里插入图片描述
2. kill掉

kill 18
  1. 然后再启动即可

热更新

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

安装

composer require hyperf/watcher --dev

发布配置

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 这个命令将废弃

php bin/hyperf.php server:watch

路由

配置文件路由

<?php
use Hyperf\HttpServer\Router\Router;

// 此处代码示例为每个示例都提供了三种不同的绑定定义方式,实际配置时仅可采用一种且仅定义一次相同的路由

// 设置一个 GET 请求的路由,绑定访问地址 '/get' 到 App\Controller\IndexController 的 get 方法
Router::get('/get', 'App\Controller\IndexController::get');
Router::get('/get', 'App\Controller\IndexController@get');
Router::get('/get', [\App\Controller\IndexController::class, 'get']);

// 设置一个 POST 请求的路由,绑定访问地址 '/post' 到 App\Controller\IndexController 的 post 方法
Router::post('/post', 'App\Controller\IndexController::post');
Router::post('/post', 'App\Controller\IndexController@post');
Router::post('/post', [\App\Controller\IndexController::class, 'post']);

// 设置一个允许 GET、POST 和 HEAD 请求的路由,绑定访问地址 '/multi' 到 App\Controller\IndexController 的 multi 方法
Router::addRoute(['GET', 'POST', 'HEAD'], '/multi', 'App\Controller\IndexController::multi');
Router::addRoute(['GET', 'POST', 'HEAD'], '/multi', 'App\Controller\IndexController@multi');
Router::addRoute(['GET', 'POST', 'HEAD'], '/multi', [\App\Controller\IndexController::class, 'multi']);

路由组

Router::addGroup('/user',function (){
    Router::get('/index', 'App\Controller\UserController::index');
    Router::post('/create', 'App\Controller\UserController::createUser');
    Router::put('/update', 'App\Controller\UserController::update');
    Router::delete('/delete', 'App\Controller\UserController::delete');
});

必填参数

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

可选参数

有时候您可能会希望这个参数是可选的,您可以通过[]来声明中括号内的参数为一个可选参数,如 /user/[{id}]

校验参数

您也可以使用正则表达式对参数进行校验,以下是一些例子

use Hyperf\HttpServer\Router\Router;

// 可以匹配 /user/42, 但不能匹配 /user/xyz
Router::addRoute('GET', '/user/{id:\d+}', 'handler');

// 可以匹配 /user/foobar, 但不能匹配 /user/foo/bar
Router::addRoute('GET', '/user/{name}', 'handler');

// 也可以匹配 /user/foo/bar as well
Router::addRoute('GET', '/user/{name:.+}', 'handler');

// 这个路由
Router::addRoute('GET', '/user/{id:\d+}[/{name}]', 'handler');
// 等同于以下的两个路由
Router::addRoute('GET', '/user/{id:\d+}', 'handler');
Router::addRoute('GET', '/user/{id:\d+}/{name}', 'handler');

// 多个可选的嵌套也是允许的
Router::addRoute('GET', '/user[/{id:\d+}[/{name}]]', 'handler');

// 这是一条无效的路由, 因为可选部分只能出现在最后
Router::addRoute('GET', '/user[/{id:\d+}]/{name}', 'handler');

注解路由

在这里插入图片描述

例如:

<?php
/**
 * OrderController.php
 *
 * Created on Orders-11:19
 * Created by xxp 332410549@qq.com
 */

namespace App\Controller;


use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Hyperf\HttpServer\Contract\RequestInterface;


/**
 * @Controller(prefix="order")
 */
class OrderController extends AbstractController
{

    /**
     * @GetMapping(path="index")
     */
    public function index(RequestInterface $request)
    {
        return 'OrderController'.$request->input('id');
    }
}

访问地址

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 文件

<?php
// config/autoload/exceptions.php
return [
    'handler' => [
        'http' => [
            Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler::class,
            App\Exception\Handler\AppExceptionHandler::class,
            App\Exception\Handler\FooExceptionHandler::class,
        ],
    ],
];


2. 定义异常处理器

app/Exception/Handler/FooExceptionHandler.php

<?php
/**
 * FooExceptionHandler.php
 *
 * Created on ExceptionHandler -13:35
 * Created by xxp 332410549@qq.com
 */

namespace App\Exception\Handler;

use App\Exception\FooException;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Psr\Http\Message\ResponseInterface;
use Throwable;

class FooExceptionHandler extends ExceptionHandler
{

    /**
     * @inheritDoc
     */
    public function handle(Throwable $throwable, ResponseInterface $response)
    {
        // 判断被捕获到的异常是希望被捕获的异常
        if ($throwable instanceof FooException) {
            // 格式化输出
            $data = json_encode([
                'code' => $throwable->getCode(),
                'message' => $throwable->getMessage(),
            ], JSON_UNESCAPED_UNICODE);

            // 阻止异常冒泡
            $this->stopPropagation();
            return $response->withStatus(500)->withBody(new SwooleStream($data));
        }

        // 交给下一个异常处理器
        return $response;
    }

    /**
     * @inheritDoc
     */
    public function isValid(Throwable $throwable): bool
    {
       return true;
    }

}
3. 定义异常类

app/Exception/FooException.php

<?php
/**
 * FooException.php
 *
 * Created on FooException-13:40
 * Created by xxp 332410549@qq.com
 */

namespace App\Exception;

use Hyperf\Server\Exception\ServerException;

class FooException extends ServerException
{


}
4. 触发异常
<?php
/**
 * OrderController.php
 *
 * Created on Orders-11:19
 * Created by xxp 332410549@qq.com
 */

namespace App\Controller;


use App\Exception\FooException;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Hyperf\HttpServer\Contract\RequestInterface;


/**
 * @Controller(prefix="order")
 */
class OrderController extends AbstractController
{

    /**
     * @GetMapping(path="index")
     */
    public function index(RequestInterface $request)
    {
        try {

            $data = [
                'code' => 0,
                'msg' => '获取成功',
                'data' => [
                    'orders' => '订单列表'
                ]
            ];
            if (1) {   // 如果没有数据,返回空数组
              throw new FooException('自定义异常');
            }
            return $this->response->json($data);
        } catch (\Exception $e) {
            return $this->response->json(['code' => 1,'msg' => $e->getMessage()]);
        }
    }



}
查看解决

在这里插入图片描述

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

Error 监听器

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

配置

在 config/autoload/listeners.php 中添加监听器

<?php
return [
    \Hyperf\ExceptionHandler\Listener\ErrorExceptionHandler::class
];

抓取错误

则当出现类似以下的代码时会抛出 \ErrorException 异常

    public function index(RequestInterface $request)
    {
        try {

            $a = [];
            ($a[1]);
            return $this->response->json($data);
        } catch (\Throwable $e) {
            return $this->response->json(['code' => 1,'msg' => $e->getMessage() ."\n num:". $e->getLine()]);
        }
    }

结果

在这里插入图片描述

中间件

原理图

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

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

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

定义局部中间件

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

通过配置文件定义

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

<?php
use App\Middleware\FooMiddleware;
use Hyperf\HttpServer\Router\Router;

// 每个路由定义方法都可接收一个 $options 参数
Router::get('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [FooMiddleware::class]]);
Router::post('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [FooMiddleware::class]]);
Router::put('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [FooMiddleware::class]]);
Router::patch('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [FooMiddleware::class]]);
Router::delete('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [FooMiddleware::class]]);
Router::head('/', [\App\Controller\IndexController::class, 'index'], ['middleware' => [FooMiddleware::class]]);
Router::addRoute(['GET', 'POST', 'HEAD'], '/index', [\App\Controller\IndexController::class, 'index'], ['middleware' => [FooMiddleware::class]]);

// 该 Group 下的所有路由都将应用配置的中间件
Router::addGroup(
    '/v2', function () {
        Router::get('/index', [\App\Controller\IndexController::class, 'index']);
    },
    ['middleware' => [FooMiddleware::class]]
);

通过注解定义

在通过注解定义路由时,您仅可通过注解的方式来定义中间件,对中间件的定义有两个注解,分别为:

#[Middleware] 注解为定义单个中间件时使用,在一个地方仅可定义一个该注解,不可重复定义
#[Middlewares] 注解为定义多个中间件时使用,在一个地方仅可定义一个该注解,然后通过在该注解内定义多个 #[Middleware] 注解实现多个中间件的定义
使用 #[Middleware] 注解时需 use Hyperf\HttpServer\Annotation\Middleware; 命名空间;
使用 #[Middlewares] 注解时需 use Hyperf\HttpServer\Annotation\Middlewares; 命名空间;

注意:必须配合 #[AutoController] 或者 #[Controller] 使用

定义单个中间件:
<?php
namespace App\Controller;

use App\Middleware\FooMiddleware;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Annotation\Middleware;

#[AutoController]
#[Middleware(FooMiddleware::class)]
class IndexController
{
    public function index()
    {
        return 'Hello Hyperf.';
    }
}
通过 #[Middlewares] 注解定义多个中间件:
<?php
namespace App\Controller;

use App\Middleware\BarMiddleware;
use App\Middleware\FooMiddleware;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Annotation\Middleware;
use Hyperf\HttpServer\Annotation\Middlewares;

#[AutoController]
#[Middlewares([FooMiddleware::class, BarMiddleware::class])]
class IndexController
{
    public function index()
    {
        return 'Hello Hyperf.';
    }
}
定义方法级别的中间件

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

<?php
namespace App\Controller;

use App\Middleware\BarMiddleware;
use App\Middleware\FooMiddleware;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Annotation\Middleware;
use Hyperf\HttpServer\Annotation\Middlewares;

#[AutoController]
#[Middlewares([FooMiddleware::class])]
class IndexController
{
    #[Middleware(BarMiddleware::class)]
    public function index()
    {
        return 'Hello Hyperf.';
    }
}

中间件相关的代码
生成中间件

php ./bin/hyperf.php gen:middleware Auth/FooMiddleware
<?php

declare(strict_types=1);

namespace App\Middleware\Auth;

use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class FooMiddleware implements MiddlewareInterface
{
    protected ContainerInterface $container;

    protected RequestInterface $request;

    protected HttpResponse $response;

    public function __construct(ContainerInterface $container, HttpResponse $response, RequestInterface $request)
    {
        $this->container = $container;
        $this->response = $response;
        $this->request = $request;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        // 根据具体业务判断逻辑走向,这里假设用户携带的token有效
        $isValidToken = true;
        if ($isValidToken) {
            return $handler->handle($request);
        }

        return $this->response->json(
            [
                'code' => -1,
                'data' => [
                    'error' => '中间件验证token无效,阻止继续向下执行',
                ],
            ]
        );
    }
}

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

中间件的执行顺序

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

在>=3.0.34的版本中,新增了优先级的配置,可以在配置方法、路由中间件的时候改变中间件的执行顺序,优先级越高,执行顺序越靠前。

// 全局中间件配置文件 middleware.php

return [
    'http' => [
        YourMiddleware::class,
        YourMiddlewareB::class => 3,
    ],
];
Copy to clipboardErrorCopied
// 路由中间件配置
Router::addGroup(
    '/v2', function () {
        Router::get('/index', [\App\Controller\IndexController::class, 'index']);
    },
    [
        'middleware' => [
            FooMiddleware::class,
            FooMiddlewareB::class => 3,
        ]
    ]
);

// 注解中间件配置

#[AutoController]
#[Middleware(FooMiddleware::class)]
#[Middleware(FooMiddlewareB::class, 3)]
#[Middlewares([FooMiddlewareC::class => 1, BarMiddlewareD::class => 4])]
class IndexController
{
    
}

全局更改请求和响应对象

首先,在协程上下文内是有存储最原始的 PSR-7 请求对象 和 响应对象 的,且根据 PSR-7 对相关对象所要求的 不可变性(immutable),也就意味着我们在调用 $response = $response->with***() 所调用得到的 $response,并非为改写原对象,而是一个 Clone 出来的新对象,也就意味着我们储存在协程上下文内的 请求对象 和 响应对象 是不会改变的,那么当我们在中间件内的某些逻辑改变了 请求对象 或 响应对象,而且我们希望对后续的 非传递性的 代码再获取改变后的 请求对象 或 响应对象,那么我们便可以在改变对象后,将新的对象设置到上下文中,如代码所示:

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

// $request 和 $response 为修改后的对象
$request = \Hyperf\Context\Context::set(ServerRequestInterface::class, $request);
$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 也可采用同样的做法来达到同样的目的。

<?php
declare(strict_types=1);

namespace App\Middleware;

use Hyperf\Contract\Arrayable;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class CoreMiddleware extends \Hyperf\HttpServer\CoreMiddleware
{
    /**
     * Handle the response when cannot found any routes.
     *
     * @return array|Arrayable|mixed|ResponseInterface|string
     */
    protected function handleNotFound(ServerRequestInterface $request)
    {
        // 重写路由找不到的处理逻辑
        return $this->response()->withStatus(404);
    }

    /**
     * Handle the response when the routes found but doesn't match any available methods.
     *
     * @return array|Arrayable|mixed|ResponseInterface|string
     */
    protected function handleMethodNotAllowed(array $methods, ServerRequestInterface $request)
    {
        // 重写 HTTP 方法不允许的处理逻辑
        return $this->response()->withStatus(405);
    }
}

然后再在 config/autoload/dependencies.php 定义对象关系重写 CoreMiddleware 对象:

<?php
return [
    Hyperf\HttpServer\CoreMiddleware::class => App\Middleware\CoreMiddleware::class,
];

这里直接重写 CoreMiddleware 的做法需要在 1.1.0+ 版本上才有效,1.0.x 版本仍需要你再将 CoreMiddleware 的上层调用通过 DI 进行重写,然后替换 CoreMiddleware 的传值为您定义的中间件类。

常用中间件

跨域中间件
如果您需要在框架中解决跨域,则可以按照您的需求实现以下中间件

<?php

declare(strict_types=1);

namespace App\Middleware;

use Hyperf\Context\Context;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class CorsMiddleware implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $response = Context::get(ResponseInterface::class);
        $response = $response->withHeader('Access-Control-Allow-Origin', '*')
            ->withHeader('Access-Control-Allow-Credentials', 'true')
            // Headers 可以根据实际情况进行改写。
            ->withHeader('Access-Control-Allow-Headers', 'DNT,Keep-Alive,User-Agent,Cache-Control,Content-Type,Authorization');

        Context::set(ResponseInterface::class, $response);

        if ($request->getMethod() == 'OPTIONS') {
            return $response;
        }

        return $handler->handle($request);
    }
}

实际上,跨域配置也可以直接挂在 Nginx 上。

location / {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
    add_header Access-Control-Allow-Headers 'DNT,Keep-Alive,User-Agent,Cache-Control,Content-Type,Authorization';

    if ($request_method = 'OPTIONS') {
        return 204;
    }
}

后置中间件
通常情况下,我们都是最后执行

return h a n d l e r − > h a n d l e ( handler->handle( handler>handle(request);
Copy to clipboardErrorCopied
所以,相当于是前置中间件,如果想要让中间件逻辑后置,其实只需要更换一下执行顺序即可。

<?php

declare(strict_types=1);

namespace App\Middleware;

use Hyperf\HttpServer\Contract\RequestInterface;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class OpenApiMiddleware implements MiddlewareInterface
{
    public function __construct(protected ContainerInterface $container)
    {
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        // TODO: 前置操作
        try{
            $result = $handler->handle($request);
        } finally {
            // TODO: 后置操作
        }
        return $result;
    }
}

实践

在这里插入图片描述

中间件文件

<?php

declare(strict_types=1);

namespace App\Middleware\Auth;

use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;

class FooMiddleware implements MiddlewareInterface
{

    /**
     * @var ContainerInterface
     */
    protected $container;

    /**
     * @var RequestInterface
     */
    protected $request;

    /**
     * @var HttpResponse
     */
    protected $response;

    public function __construct(ContainerInterface $container, HttpResponse $response, RequestInterface $request)
    {
        $this->container = $container;
        $this->response = $response;
        $this->request = $request;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $isValidToken = true;
        if ($isValidToken) {
            return $handler->handle($request);
        }

        return $this->response->json(
            [
                'code' => -1,
                'data' => [
                    'error' => '中间件验证token无效,阻止继续向下执行 ',
                ],
            ]
        );
    }
}

$isValidToken 根据具体业务来判断
如果为真,则放行
如果为假,则阻断

中间件调用

<?php
/**
 * Message.php
 *
 * Created on Message-15:28
 * Created by xxp 332410549@qq.com
 */

namespace App\Controller;

use Hyperf\HttpServer\Annotation\AutoController;
use App\Controller\AbstractController;
use Hyperf\HttpServer\Annotation\Middleware;
use App\Middleware\Auth\FooMiddleware;
/**
 * @AutoController()
 * @Middleware(FooMiddleware::class)
 */
class MessageController extends AbstractController
{

    public function index()
    {
        return 'message';
    }
}

结果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2047106.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【免费】最新区块链钱包和私钥的助记词碰撞器,bybit使用python开发

使用要求 1、用的是google里面的扩展打包成crx文件&#xff0c;所以在使用之前你需要确保自己电脑上有google浏览器&#xff0c;而且google浏览器版本需要在124之上。&#xff08;要注意一下&#xff0c;就是电脑只能有一个Chrome浏览器&#xff09; 2、在win10上用vscode开发…

网络编程:OSI协议,TCP/IP协议,IP地址,UDP编程

目录 国际网络通信协议标准&#xff1a; 1.OSI协议&#xff1a; 2.TCP/IP协议模型&#xff1a; 应用层 &#xff1a; 传输层&#xff1a; 网络层&#xff1a; IPV4协议 IP地址 IP地址的划分&#xff1a; 公有地址 私有地址 MA…

jmeter引入jar包的三种方式

示例 实现对登录密码进行MD5加密 pom文件依赖 <!-- https://mvnrepository.com/artifact/commons-codec/commons-codec --><dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.12&l…

安全密码算法:SM3哈希算法介绍

最靠谱的是看标准文档&#xff01; 1. 简介 国密算法之一&#xff0c;哈希算法的一种&#xff0c;也是密码杂凑算法。可以将不定长的输入消息message&#xff0c;经过SM3算法计算后输出为32B固定长度的哈希值&#xff08;hash value&#xff09;。哈希算法的实质是单向散列函…

Java | Leetcode Java题解之第343题整数拆分

题目&#xff1a; 题解&#xff1a; class Solution {public int integerBreak(int n) {if (n < 3) {return n - 1;}int quotient n / 3;int remainder n % 3;if (remainder 0) {return (int) Math.pow(3, quotient);} else if (remainder 1) {return (int) Math.pow(3…

使用 Python 进行 PDF 文件加密

使用 Python 解密加密的 PDF 文件-CSDN博客定义一个名为的函数&#xff0c;该函数接受三个参数&#xff1a;输入的加密 PDF 文件路径input_pdf、输出的解密 PDF 文件路径output_pdf和密码password。https://blog.csdn.net/qq_45519030/article/details/141256661 在数字化时代…

[Linux][OS][详解信号的产生]

目录 1.信号概念 硬件层面 2. 产生! 1. 键盘组合键 2. kill 命令 kill -signo pid 3. 系统调用 4. 硬件异常--会自动退出 软件条件--闹钟 发送 信号和信号量没有任何的关系&#xff0c;就像老婆和老婆饼&#xff0c;上一篇文章我们讲到了信号量&#xff0c;这篇文章我…

探索未来教育新形态:基于AI大模型的在线辅导平台LlamaTutor

在数字化时代,教育的边界正在被重新定义。今天,我们将深入探索一款创新的教育工具——LlamaTutor,一个基于AI大模型的在线个人辅导平台,它利用前沿技术为学习者带来前所未有的个性化学习体验。 引言 随着人工智能技术的飞速发展,AI在教育领域的应用日益广泛。LlamaTutor…

冰岛数据中心技术三巨头推出由可再生能源驱动的一体化云计算解决方案

冰岛通过国内生产的各种形式的可再生能源来满足其大部分能源需求。据三家开发新数据中心服务的公司称&#xff0c;这个北欧岛国也是关键任务云应用的理想环境。 Vespertec 公司、Sardina Systems 公司和 Borealis 公司共同开发了一种创新的 IT 解决方案&#xff0c;名为冰云综合…

MATLAB算法实战应用案例精讲-【人工智能】差分隐私(概念篇)

目录 前言 知识储备 算法原理 发展历程 差分隐私的引入 GIC 事件 ε(epsilon)-差分隐私​编辑 实现方式 什么是差分隐私 差分隐私的工作原理 数学模型 差分隐私计算公式 拉普拉斯机制 高斯机制 高斯机制满足 (ε,δ)-差分隐私的数学证明 可组合性 怎样在机…

Python版《超级玛丽+源码》-Python制作超级玛丽游戏

小时候最喜欢玩的小游戏就是超级玛丽了&#xff0c;有刺激有又技巧&#xff0c;通关真的很难&#xff0c;救下小公主还被抓走了&#xff0c;唉&#xff0c;心累&#xff0c;最后还是硬着头皮继续闯&#xff0c;终于要通关了&#xff0c;之后再玩还是没有那么容易&#xff0c;哈…

思科OSPF动态路由配置8

#路由协议实现# #任务八OSPF动态路由配置8# 开放式最短路径优先&#xff08;Open Shortest Path First,OSPF&#xff09;协议是目前网络中应用最广泛的动态路由协议之一。它也属于内部网关路由协议&#xff0c;能够适应各种规模的网络环境&#xff0c;是典型的链路状态路由协…

JavaScript初级——简介

一、什么是语言 1、计算机就是一个由人来控制的机器。 2、我们要学习的语言就是人和计算机交流的工具&#xff0c;人类通过语言来控制、操作计算机。 3、编程语言和我们说的中文、英文本质上没有区别&#xff0c;只是语法比较特殊。 4、语言的发展&#xff1a; —纸带机&#x…

“低代码” 风暴:重塑软件开发新未来

目录 引言&#xff1a; 正文&#xff1a; 方向一&#xff1a;技术概览 方向二&#xff1a;效率与质量的权衡 方向三&#xff1a;挑战与机遇 结束语&#xff1a; 引言&#xff1a; 在当今数字化高速发展的时代&#xff0c;技术的创新如同璀璨星辰不断照亮我们前行的道路。“…

Dijikstra算法(堆优化版)

当给定数据的范围不大时&#xff0c;采用朴素Dijikstra算法尚能ac&#xff0c;但若是数据范围大于10^5&#xff0c;那么朴素Dijikstra算法就会爆掉&#xff0c;所以我们需要采用堆优化版的Dijikstra算法 堆优化版Dijikstra主要是对朴素Dijikstra中找寻从距离编号 1 结点路径长…

突然肾结石了:这时候我才意识到问题

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 中午吃过饭&#xff0c;下腹剧痛&#xff0c;忍了2个小时&#xff0c;我以为是普通肚子痛&#xff0c;因为之前没有任何征兆&#xff0c;所以我忍痛拍了这个视频。 这也是为什么评论区有朋友说&#xff1a;这期视频…

BQ27441初始化配置程序,电压、SOC等参数读取程序

系列文章目录 1.元件基础 2.电路设计 3.PCB设计 4.元件焊接 5.板子调试 6.程序设计 7.算法学习 8.编写exe 9.检测标准 10.项目举例 11.职业规划 文章目录 前言一、模拟IIC二、BQ27441初始化配置程序三、学习资料 前言 送给大学毕业后找不到奋斗方向的你&#xff08;每周不定…

算法打卡 Day23(二叉树)-二叉搜索树的最小绝对差 + 二叉搜索树中的众数 + 二叉树的最近公共祖先

文章目录 Leetcode 530-二叉搜索树的最小绝对差题目描述解题思路 Leetcode 501-二叉搜索树中的众数题目描述解题思路 Leetcode 236-二叉树的最近公共祖先题目描述解题思路 Leetcode 530-二叉搜索树的最小绝对差 题目描述 https://leetcode.cn/problems/minimum-absolute-diff…

萌啦数据使用多久,萌啦数据价格表2024

在数字化浪潮汹涌的今天&#xff0c;数据已成为企业决策与业务增长的核心驱动力。在众多数据分析工具中&#xff0c;萌啦数据凭借其强大的数据处理能力、直观的数据可视化效果以及灵活的数据分析模型&#xff0c;赢得了众多企业和个人的青睐。那么&#xff0c;关于“萌啦数据使…

C++ | Leetcode C++题解之第341题扁平化嵌套列表迭代器

题目&#xff1a; 题解&#xff1a; class NestedIterator { private:vector<int> vals;vector<int>::iterator cur;void dfs(const vector<NestedInteger> &nestedList) {for (auto &nest : nestedList) {if (nest.isInteger()) {vals.push_back(n…