用hyperf框架开发JsonRpc服务

按照官网文档创建好hyperf项目开发容器,我在容器内部创建了role_manage项目,提供服务的srv项目和服务客户端client。

开发rpc接口流程

首先创建服务提供者srv,以下命令都是在srv目录下的命令行工具中执行

1.创建项目

创建项目时选择了jsonrpc协议

2.创建rpc服务

2.1安装和配置相关组件

在srv目录的终端执行

composer require hyperf/json-rpc
composer require hyperf/rpc-server
composer require hyperf/rpc-client

将服务注册到consul,需要安装一下组件

composer require hyperf/service-governance

发布组件

php bin/hyperf.php vendor:publish hyperf/consul

则自动在config/autoload/目录下自动生成consul.php配置文件

在consul.php配置consul相关内容

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://doc.hyperf.io
 * @contact  [email protected]
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
return [
    'uri' => 'http://192.168.47.135:8500',
];

2.2创建服务

在app下新增JsonRpc目录

新建RoleService.php文件,使用RpcService注解配置rpc服务

<?php
/**
 * Created by PhpStorm.
 * User: hengben
 * Date: 4/30/20
 * Time: 1:01 AM
 */

namespace App\JsonRpc;

use Hyperf\RpcServer\Annotation\RpcService;

/**
 *
 * @RpcService(name="RoleService", protocol="jsonrpc-http", server="jsonrpc-http", publishTo="consul")
*/
class RoleService
{
    
    
    //public function addCategory(array $attributes = [])
    public function addCategory(array $attributes = [])
    {
    
    
        return 1;
    }
}

在config/autoload/server.php配置角色管理服务

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://doc.hyperf.io
 * @contact  [email protected]
 * @license  https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
 */

use Hyperf\Server\Server;
use Hyperf\Server\SwooleEvent;

return [
    'mode' => SWOOLE_PROCESS,
    'servers' => [
        [
            'name' => 'http',
            'type' => Server::SERVER_HTTP,
            'host' => '0.0.0.0',
            'port' => 9501,
            'sock_type' => SWOOLE_SOCK_TCP,
            'callbacks' => [
                SwooleEvent::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
            ],
        ],
        [
            'name' => 'jsonrpc-http',
            'type' => Server::SERVER_HTTP,
            'host' => '0.0.0.0',
            'port' => 9504,
            'sock_type' => SWOOLE_SOCK_TCP,
            'callbacks' => [
                //SwooleEvent::ON_REQUEST => [Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
                SwooleEvent::ON_REQUEST => [Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
            ],
        ],
    ],
    'settings' => [
        'enable_coroutine' => true,
        'worker_num' => swoole_cpu_num(),
        'pid_file' => BASE_PATH . '/runtime/hyperf.pid',
        'open_tcp_nodelay' => true,
        'max_coroutine' => 100000,
        'open_http2_protocol' => true,
        'max_request' => 100000,
        'socket_buffer_size' => 2 * 1024 * 1024,
        'buffer_output_size' => 2 * 1024 * 1024,
    ],
    'callbacks' => [
        SwooleEvent::ON_BEFORE_START => [Hyperf\Framework\Bootstrap\ServerStartCallback::class, 'beforeStart'],
        SwooleEvent::ON_WORKER_START => [Hyperf\Framework\Bootstrap\WorkerStartCallback::class, 'onWorkerStart'],
        SwooleEvent::ON_PIPE_MESSAGE => [Hyperf\Framework\Bootstrap\PipeMessageCallback::class, 'onPipeMessage'],
    ],
];

3.创建数据表模型

涉及使用到的数据表

CREATE TABLE IF NOT EXISTS `role_category` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT, #主键
  `name` varchar(50) NOT NULL DEFAULT '', #分类名
  `sort` tinyint(3) unsigned NOT NULL DEFAULT 0, #排序
  `status` tinyint(3) unsigned NOT NULL DEFAULT 0, #是否启用(1启用, 2禁用)
  `description` varchar(255) NOT NULL DEFAULT '', #描述
  `is_deleted` tinyint(1) unsigned NOT NULL DEFAULT 0, #是否删除(1未删除, 2删除)
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3.1修改数据库连接配置文件

首先需要配置配置文件使其能连接上数据库

在.env文件配置如下:

APP_NAME=skeleton

DB_DRIVER=mysql
DB_HOST=192.168.47.135
DB_PORT=3306
DB_DATABASE=role_manage
DB_USERNAME=root
DB_PASSWORD=root
DB_CHARSET=utf8mb4
DB_COLLATION=utf8mb4_unicode_ci
DB_PREFIX=

REDIS_HOST=192.168.47.135
REDIS_AUTH=(null)
REDIS_PORT=6379
REDIS_DB=0

在config/autoload/databases.php配置如下:

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://doc.hyperf.io
 * @contact  [email protected]
 * @license  https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
 */

return [
    'default' => [
        'driver' => env('DB_DRIVER', 'mysql'),
        'host' => env('DB_HOST', '192.168.47.135'),
        'database' => env('DB_DATABASE', 'role-manage'),
        'port' => env('DB_PORT', 3306),
        'username' => env('DB_USERNAME', 'root'),
        'password' => env('DB_PASSWORD', 'rootcd'),
        'charset' => env('DB_CHARSET', 'utf8'),
        'collation' => env('DB_COLLATION', 'utf8_unicode_ci'),
        'prefix' => env('DB_PREFIX', ''),
        'pool' => [
            'min_connections' => 1,
            'max_connections' => 10,
            'connect_timeout' => 10.0,
            'wait_timeout' => 3.0,
            'heartbeat' => -1,
            'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),
        ],
        'commands' => [
            'gen:model' => [
                'path' => 'app/Model',
                'force_casts' => true,
                'inheritance' => 'Model',
            ],
        ],
    ],
];

3.2创建模型

然后在srv目录下的终端执行

php bin/hyperf.php gen:model role_category

之后再app/Model目录下创建出RoleCategory.php文件

因为需要将批量新增多个字段数据需要在RoleCategory.php模型文件中设置fillable,并且因为数据表中没有created_at和updated_at等时间字段,需要将时间格式化关闭,所以模型文件配置如下:

<?php

declare (strict_types=1);
namespace App\Model;

use Hyperf\DbConnection\Model\Model;
/**
 * @property int $id 
 * @property string $name 
 * @property int $sort 
 * @property int $status 
 * @property string $description 
 * @property int $is_deleted 
 */
class RoleCategory extends Model
{
    
    
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'role_category';
    /**
     *
     * 不维护时间格式
    */
    public $timestamps = false;
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['name', 'sort', 'status', 'description', 'is_deleted'];
    //protected $fillable = [];
    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = ['id' => 'integer', 'sort' => 'integer', 'status' => 'integer', 'is_deleted' => 'integer'];
}

4.创建异常处理

终端执行

composer require hyperf/constants

4.1定义错误码常量

在app目录下创建Constants文件夹,在Constants下创建ErrorCode.php

<?php
/**
 * Created by PhpStorm.
 * User: hengben
 * Date: 5/5/20
 * Time: 11:23 PM
 */
declare(strict_types=1);

namespace App\Constants;

use Hyperf\Constants\AbstractConstants;
use Hyperf\Constants\Annotation\Constants;

/**
 * @Constants
 */
class ErrorCode extends AbstractConstants
{
    
    
    /**
     * @Message("Request Error!")
    */
    const ERROR = 0;

    /**
     * @Message("Success")
     */
    const SUCCESS = 200;

    /**
     * @Message("验证错误!")
     */
    const VALIDATE_ERROR = 422;

    /**
     * @Message("无权访问该资源")
     */
    const DISALLOW = 403;

    /**
     * @Message("请求参数错误!")
     */
    const BAD_REQUEST = 400;

    /**
     * @Message("请先登录")
     */
    const NOT_LOGGED_IN = 401;

    /**
     * @Message("请求资源不存在!")
     */
    const RECORD_NOT_FOUND = 404;

    /**
     * @Message("方法不允许访问!")
     */
    const METHOD_NOT_ALLOWED = 405;

    /**
     * @Message("保存数据失败,请重试!")
     */
    const SAVE_DATA_FAIL = 1001;

    /**
     * @Message("查询异常!")
     */
    const QUERYEXCEPTION = 1002;

    /**
     * @Message("用户名或者密码错误!")
     */
    const INCORRECT_PASSWORD = 1003;

    /**
     * @Message("请求参数错误")
     */
    const PARAMS_ERROR = 1005;

    /**
     * @Message("资源已禁用")
     */
    const DATA_DISABLE = 1007;

    /**
     * @Message("名称已存在!")
     */
    const NAMEALREADYEXIST = 1008;

    /**
     * @Message("token验证不通过!")
     */
    const TOKENMISMATCH = 1010;
}

4.2定义公共方法

在app目录下创建Common文件,然后创建Common.php文件

<?php
/**
 * Created by PhpStorm.
 * User: hengben
 * Date: 5/6/20
 * Time: 2:57 AM
 */

namespace App\Common;

use App\Constants\ErrorCode;

class Common
{
    
    
    //返回成功
    public function success($data)
    {
    
    
        return $this->result(ErrorCode::SUCCESS, ErrorCode::getMessage(ErrorCode::SUCCESS), $data);
    }

    //返回错误
    public function error($code = ErrorCode::REQUEST_FAIL, $message = '', $data = [])
    {
    
    
        if (empty($message)) {
    
    
            return $this->result($code, ErrorCode::getMessage($code), $data);
        } else {
    
    
            return $this->result($code, $message, $data);
        }
    }

    public function result($code, $message, $data)
    {
    
    
        return ['code' => $code, 'message' => $message, 'data' => $data];
    }

    public function jsonEncode($data)
    {
    
    
        return json_encode($data, JSON_UNESCAPED_UNICODE);
    }
}

4.3异常处理

定义异常类

在app\Exception目录下创建BusinessException.php

<?php
/**
 * Created by PhpStorm.
 * User: hengben
 * Date: 5/5/20
 * Time: 11:52 PM
 */
declare(strict_types = 1);

namespace App\Exception;

use App\Constants\ErrorCode;
use Hyperf\Server\Exception\ServerException;
use Throwable;


class BusinessException extends ServerException
{
    
    
    public function __construct(int $code = 0, string $message = null, Throwable $previous = null)
    {
    
    
        if (is_null($message)) {
    
    
            $message = ErrorCode::getMessage($code);
        }

        parent::__construct($message, $code, $previous);
    }
}

在app\Exception\Handler下创建BusinessException异常类的处理器BusinessExceptionHandler.php

<?php
/**
 * Created by PhpStorm.
 * User: hengben
 * Date: 5/6/20
 * Time: 5:53 PM
 */
declare(strict_types = 1);

namespace App\Exception\Handler;

use Hyperf\Di\Annotation\Inject;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Psr\Http\Message\ResponseInterface;
use App\Exception\BusinessException;
use Throwable;
use App\Common\Common;
use App\Constants\ErrorCode;

class BusinessExceptionHandler extends  ExceptionHandler
{
    
    
    /**
     * @Inject
     * @var Common
    */
    protected $common;

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

            // 阻止异常冒泡
            $this->stopPropagation();

            //return $result;
            return $response->withStatus(200)->withBody(new SwooleStream($data));
        }

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

    }

    public function isValid(Throwable $throwable): bool
    {
    
    
        return true;
    }
}

注册异常处理器BusinessExceptionHandler

在config\autoload\exceptions.php中注册异常处理器

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://doc.hyperf.io
 * @contact  [email protected]
 * @license  https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
 */

return [
    'handler' => [
        'http' => [
            App\Exception\Handler\AppExceptionHandler::class,
            App\Exception\Handler\BusinessExceptionHandler::class,
        ],
        'jsonrpc-http' => [
            App\Exception\Handler\AppExceptionHandler::class,
            App\Exception\Handler\BusinessExceptionHandler::class,
        ],
    ],
];

5.实现新增分类接口逻辑

实现新增分类接口,并且使用上自定义的异常类BusinessException

<?php
/**
 * Created by PhpStorm.
 * User: hengben
 * Date: 4/30/20
 * Time: 1:01 AM
 */

namespace App\JsonRpc;

use Hyperf\RpcServer\Annotation\RpcService;
use App\Model\RoleCategory;
use App\Constants\ErrorCode;
use App\Exception\BusinessException;
use Hyperf\DbConnection\Db;


/**
 *
 * @RpcService(name="RoleService", protocol="jsonrpc-http", server="jsonrpc-http", publishTo="consul")
*/
class RoleService implements RoleServiceInterface
{
    
    
    /**
     * 添加角色分类
     *
    */
    public function addCategory(array $attributes = [])
    {
    
    

        if ($attributes['name']) {
    
    

            $catecory = RoleCategory::query()->where('name', $attributes['name'])->first();

            if ($catecory) {
    
    
                //throw NameAlreadyExists::create($attributes['name']);
                throw new BusinessException(ErrorCode::NAMEALREADYEXIST,"名称[".$attributes['name']."]已经存在");
            }

            $result = null;

            Db::beginTransaction();
            try{
    
    

                if ($attributes['sort']) {
    
    

                    //更改大于等于输入排序值的数据本身排序的加1
                    RoleCategory::query()->where('sort','>=', $attributes['sort'])->increment('sort',1);

                }

                $result = RoleCategory::query()->create($attributes);

                Db::commit();

            } catch(\Throwable $ex){
    
    

                Db::rollBack();

                throw new BusinessException(ErrorCode::SAVE_DATA_FAIL);

            }

            return $result;
        } else {
    
    
            return '分类名必须';
        }
    }

}

将服务类方法抽象为接口,创建RoleServiceInterface.php文件

<?php
/**
 * Created by PhpStorm.
 * User: hengben
 * Date: 5/5/20
 * Time: 1:34 AM
 */
namespace App\JsonRpc;

/**
 * 将类方法抽象为接口
*/
interface RoleServiceInterface
{
    
    
    public function addCategory(array $attributes = []);
}

6.验证rpc接口

postman发起请求json请求

url:http://127.0.0.1:9504

请求方式:POST

选择raw,格式选择json

{
    
    
    "jsonrpc":"2.0",
    "method":"/role/addCategory",
    "params":[{
    
    "name":"hahha13","sort":6}],
    "id":"0"
}

成功则返回

{
    
    
    "jsonrpc": "2.0",
    "id": "0",
    "result": {
    
    
        "code": 1008,
        "message": "名称[hahha14]已经存在",
        "data": []
    },
    "context": []
}

开发对外HTTP接口流程

1.创建项目

将srv的框架复制并且重命名为client

2.创建rpc服务客户端

2.1安装和配置相关组件

所有命令在client目录下的终端执行

因为是复制srv项目,所以相关组件已经安装好了。如果重新创建,步骤请参照RPC接口流程中的创建RPC服务

在app目录下创建一个JsonRpc目录,将srv\app\JsonRpc目录下的RoleServiceInterface.php文件复制过来,这个就是相当于中间协议文件

在config\autoload目录下创建一个services.php的配置文件,配置如下

<?php
/**
 * Created by PhpStorm.
 * User: hengben
 * Date: 5/6/20
 * Time: 12:58 AM
 */

return [
    'consumers' => [
        [
            // name 需与服务提供者的 name 属性相同
            'name' => 'RoleService',
            // 服务接口名,可选,默认值等于 name 配置的值,如果 name 直接定义为接口类则可忽略此行配置,如 name 为字符串则需要配置 service 对应到接口类
            'service' => \App\JsonRpc\RoleServiceInterface::class,
            // 对应容器对象 ID,可选,默认值等于 service 配置的值,用来定义依赖注入的 key
            'id' => \App\JsonRpc\RoleServiceInterface::class,
            // 服务提供者的服务协议,可选,默认值为 jsonrpc-http
            // 可选 jsonrpc-http jsonrpc jsonrpc-tcp-length-check
            'protocol' => 'jsonrpc-http',
            // 负载均衡算法,可选,默认值为 random
            'load_balancer' => 'random',
            // 这个消费者要从哪个服务中心获取节点信息,如不配置则不会从服务中心获取节点信息
            'registry' => [
                'protocol' => 'consul',
                'address' => 'http://192.168.47.135:8500',
            ],

            // 配置项,会影响到 Packer 和 Transporter
            'options' => [
                'connect_timeout' => 5.0,
                'recv_timeout' => 5.0,
                'settings' => [
                    // 根据协议不同,区分配置
                    'open_eof_split' => true,
                    'package_eof' => "\r\n",
                    // 'open_length_check' => true,
                    // 'package_length_type' => 'N',
                    // 'package_length_offset' => 0,
                    // 'package_body_offset' => 4,
                ],
                // 当使用 JsonRpcPoolTransporter 时会用到以下配置
                'pool' => [
                    'min_connections' => 1,
                    'max_connections' => 32,
                    'connect_timeout' => 10.0,
                    'wait_timeout' => 3.0,
                    'heartbeat' => -1,
                    'max_idle_time' => 60.0,
                ],
            ],
        ]
    ],
];

还需要查看一下server.php的配置有没有和服务提供者的配置有冲突,一般是端口的冲突,这里我注释掉了srv中的http接口的配置

'servers' => [
        /*[
            'name' => 'http',
            'type' => Server::SERVER_HTTP,
            'host' => '0.0.0.0',
            'port' => 9501,
            'sock_type' => SWOOLE_SOCK_TCP,
            'callbacks' => [
                SwooleEvent::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
            ],
        ],*/
        [
            'name' => 'jsonrpc-http',
            'type' => Server::SERVER_HTTP,
            'host' => '0.0.0.0',
            'port' => 9504,
            'sock_type' => SWOOLE_SOCK_TCP,
            'callbacks' => [
                //SwooleEvent::ON_REQUEST => [Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
                SwooleEvent::ON_REQUEST => [Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
            ],
        ],
    ],

2.2自动创建服务消费者

没有问题之后,启动client的服务之后就会自动生成服务消费者类

在client下的终端执行

php bin/hyperf.php start

3.创建HTTP接口验证器

3.1配置验证器组件

安装hyperf/validation组件包

终端执行

composer require hyperf/validation

添加验证器中间件,在config/autoload/middlewares.php配置文件加上一个全局中间件Hyperf\Validation\Middleware\ValidationMiddleware的配置

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://doc.hyperf.io
 * @contact  [email protected]
 * @license  https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
 */

return [
    'http' => [
        //定义全局中间件
        Hyperf\Validation\Middleware\ValidationMiddleware::class,
    ],
];

发布 Translation 组件的文件:

php bin/hyperf.php vendor:publish hyperf/translation

发布验证器组件的文件:

php bin/hyperf.php vendor:publish hyperf/validation

3.2创建表单请求验证

终端执行:

php bin/hyperf.php gen:request RoleCategoryRequest

表单验证类会生成于app\Request目录下。

在里面添加验证规则,常见的验证规则会根据场景的不同而不同,例如新增和编辑的必填项不一样

<?php

declare(strict_types=1);

namespace App\Request;

use Hyperf\Validation\Request\FormRequest;

class RoleCategoryRequest extends FormRequest
{
    
    
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
    
    
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     */
    public function rules(): array
    {
    
    
        //var_dump($this->path());

        //根据请求场景来写规则
        switch ($this->path())
        {
    
    
            case 'role/category/add':
                {
    
    
                    return [
                        'name' => 'required|max:50',
                    ];
                }
            case 'role/category/edit':
                {
    
    
                    return [
                        'id' => 'required',
                        'name' => 'required|max:50',
                    ];
                }
            default:
                {
    
    
                    return [];
                }
        }


        /*return [
            'name' => 'required|max:50',
        ];*/
    }
}

3.3配置验证异常类

在config/autoload/exception.php中配置异常类

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://doc.hyperf.io
 * @contact  [email protected]
 * @license  https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
 */

return [
    'handler' => [
        'http' => [
            App\Exception\Handler\AppExceptionHandler::class,
            //配置验证器异常类
            Hyperf\Validation\ValidationExceptionHandler::class,
        ],
    ],
];

4.创建公共方法(复制srv里面)

4.2定义错误码常量

将srv中的错误码常量服务过来,然后安装组件

composer require hyperf/constants

4.2创建公共函数

在app目录下创建Common目录,再创建common.php

<?php
/**
 * Created by PhpStorm.
 * User: hengben
 * Date: 5/6/20
 * Time: 2:57 AM
 */

namespace App\Common;

use App\Constants\ErrorCode;

class Common
{
    
    
    //返回成功
    public function success($data)
    {
    
    
        return $this->result(ErrorCode::SUCCESS, ErrorCode::getMessage(ErrorCode::SUCCESS), $data);
    }

    //返回错误
    public function error($code = ErrorCode::REQUEST_FAIL, $message = '', $data = [])
    {
    
    
        if (empty($message)) {
    
    
            return $this->result($code, ErrorCode::getMessage($code), $data);
        } else {
    
    
            return $this->result($code, $message, $data);
        }
    }

    public function result($code, $message, $data)
    {
    
    
        return ['code' => $code, 'message' => $message, 'data' => $data];
    }

    public function jsonEncode($data)
    {
    
    
        return json_encode($data, JSON_UNESCAPED_UNICODE);
    }
}

4.创建控制器和路由

4.1创建角色分勒控制器和路由

创建CategoryController控制器

<?php
/**
 * Created by PhpStorm.
 * User: hengben
 * Date: 5/6/20
 * Time: 2:13 AM
 */

namespace App\Controller;

use App\Request\RoleCategoryRequest;


class CategoryController
{
    
    
    public function add(RoleCategoryRequest $request)
    {
    
    
        $validated = $request->validated();

        return $validated;
    }
}

配置路由

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://doc.hyperf.io
 * @contact  [email protected]
 * @license  https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
 */

use Hyperf\HttpServer\Router\Router;

Router::addRoute(['GET', 'POST', 'HEAD'], '/', 'App\Controller\IndexController@index');
Router::addRoute(['GET', 'POST', 'HEAD'], '/role/category/add', 'App\Controller\CategoryController@add');

4.2验证验证规则

postman发起请求

url:http://127.0.0.1:9501/role/category/add

请求方式:POST

表单类型:什么都不写

结果返回

name 字段是必须的

在控制中调用角色服务里面的创建分类rpc接口

4.3调用角色服务的创建分类rpc接口

<?php
/**
 * Created by PhpStorm.
 * User: hengben
 * Date: 5/6/20
 * Time: 2:13 AM
 */

namespace App\Controller;

use App\Request\RoleCategoryRequest;
use Hyperf\Utils\ApplicationContext;
use App\JsonRpc\RoleServiceInterface;


class CategoryController extends AbstractController
{
    
    
    public function add(RoleCategoryRequest $request)
    {
    
    

        $validated = $request->validated();
        var_dump($validated);

        $client = ApplicationContext::getContainer()->get(RoleServiceInterface::class);

        $result = $client->addCategory($validated);

        return $result;
    }
}

5.验证HTTP接口

postman发起请求

url:

请求方式:POST

表单类型:form-data

name:hehhe14

添加成功结果返回

{
    "name": "hehhe14",
    "id": 21
}

6.在服务客户端定义跨域中间件

创建corsMiddleware中间件

在client下的终端执行

php ./bin/hyperf.php gen:middleware Cors/CorsMiddleware

会在app\Middleware目录下生成Cors/CorsMiddleware.php

在里面做如下修改

<?php

declare(strict_types=1);

namespace App\Middleware\Cors;

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

class CorsMiddleware implements MiddlewareInterface
{
    
    
    /**
     * @var ContainerInterface
     */
    protected $container;

    public function __construct(ContainerInterface $container)
    {
    
    
        $this->container = $container;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
    
    
        $response = Context::get(ResponseInterface::class);
        $response = $response->withHeader('Access-Control-Allow-Origin','*')
            ->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);
    }
}

定义全局中间件

在config\autoload\middlewares.php定义跨域中间件

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://doc.hyperf.io
 * @contact  [email protected]
 * @license  https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
 */

return [
    'http' => [
        //定义全局中间件
        Hyperf\Validation\Middleware\ValidationMiddleware::class,
        App\Middleware\Cors\CorsMiddleware::class,
    ],
];

注册中间件和处理器时一定要注意哪个服务使用,不对应的话注册会无法生效

猜你喜欢

转载自blog.csdn.net/qq_23257451/article/details/125555809