带你轻松使用Hyperf玩转Grpc(六)服务发现
六、服务发现
前面,我们已经将服务实现并注册到 nacos了。下面我们将完成api项目,并从nacos发现并使用服务。
进入 code/api/mall-api 目录中 执行
(小白须知:可以再开个命令行窗口,docker exec -it mall-php /bin/bash 进入容器,之前跑的 服务就不用关掉了 )
composer require crayoon/hyperf-grpc-client
引入我们需要的插件。并执行
php bin/hyperf.php vendor:publish crayoon/hyperf-grpc-client
生成配置文件,同理 我们需要关注 nacos 的配置,还不清楚在哪配置的 移步下 上一篇哈。
1、生成代码
在 mall-api 根目录中执行
protoc --php_out=./ --grpc_out=./ --plugin=protoc-gen-grpc=/usr/local/lib/grpc_php_plugin -I=/app/proto product_srv.proto
在 app/Grpc 目录下新建 GrpcClient 目录
需要复制 app/Grpc/Mall/ProductSrv/ProductSrvClient 到 app/Grpc/GrpcClient 目录下并且修改
<?php
namespace App\Grpc\GrpcClient;
use Crayoon\HyperfGrpcClient\BaseGrpcClient;
/**
*/
class ProductSrvClient extends BaseGrpcClient { //父类换成 Crayoon\HyperfGrpcClient\BaseGrpcClient
//注意这里的 构造方法去除
/**
* @param \App\Grpc\Mall\ProductSrv\ProductCreateRequest $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return array //返回 替换成 array
*/
public function create(\App\Grpc\Mall\ProductSrv\ProductCreateRequest $argument,
$metadata = [], $options = []) {
return $this->_simpleRequest('/mall.ProductSrv/create',
$argument,
['\App\Grpc\Mall\ProductSrv\ProductId', 'decode'],
$metadata, $options);
}
/**
* @param \App\Grpc\Mall\ProductSrv\ProductListRequest $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return array
*/
public function getList(\App\Grpc\Mall\ProductSrv\ProductListRequest $argument,
$metadata = [], $options = []) {
return $this->_simpleRequest('/mall.ProductSrv/getList',
$argument,
['\App\Grpc\Mall\ProductSrv\ProductListReply', 'decode'],
$metadata, $options);
}
/**
* @param \App\Grpc\Mall\ProductSrv\ProductId $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return array
*/
public function getStock(\App\Grpc\Mall\ProductSrv\ProductId $argument,
$metadata = [], $options = []) {
return $this->_simpleRequest('/mall.ProductSrv/getStock',
$argument,
['\App\Grpc\Mall\ProductSrv\ProductStockReply', 'decode'],
$metadata, $options);
}
/**
* @param \App\Grpc\Mall\ProductSrv\ProductStockRequest $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return array
*/
public function incStock(\App\Grpc\Mall\ProductSrv\ProductStockRequest $argument,
$metadata = [], $options = []) {
return $this->_simpleRequest('/mall.ProductSrv/incStock',
$argument,
['\App\Grpc\Mall\ProductSrv\ProductStockReply', 'decode'],
$metadata, $options);
}
/**
* @param \App\Grpc\Mall\ProductSrv\ProductStockRequest $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return array
*/
public function decStock(\App\Grpc\Mall\ProductSrv\ProductStockRequest $argument,
$metadata = [], $options = []) {
return $this->_simpleRequest('/mall.ProductSrv/decStock',
$argument,
['\App\Grpc\Mall\ProductSrv\ProductStockReply', 'decode'],
$metadata, $options);
}
}
2、编写控制器
并通过注入获取请求客户端
<?php
namespace App\Controller;
use App\Grpc\GrpcClient\ProductSrvClient;
use App\Grpc\Mall\ProductSrv\Product;
use App\Grpc\Mall\ProductSrv\ProductCreateRequest;
use App\Grpc\Mall\ProductSrv\ProductId;
use App\Grpc\Mall\ProductSrv\ProductListReply;
use App\Grpc\Mall\ProductSrv\ProductListRequest;
use Hyperf\Grpc\StatusCode;
//注意这里引入的是 修改后的客户端
class ProductController extends AbstractController
{
public function __construct(
protected ProductSrvClient $productSrvClient
)
{
}
public function create(): array
{
$param = $this->request->post();
//@todo 这里需要验证器验证传参,略
[$reply, $status] = $this->productSrvClient->create(
(new ProductCreateRequest())
->setTitle($param['title'] ?? '')
->setIcon($param['icon'] ?? '')
->setStock($param['stock'] ?? 0)
);
if ($status != StatusCode::OK) {
//就直接报错啦
return [
"code" => 1,
"message" => $reply ?? 'fail'
];
}
/**
* @var ProductId $reply
*/
return [
"code" => 0,
"message" => 'ok',
"data" => ["id" => $reply->getId()]
];
}
public function list(): array
{
$param = $this->request->query();
[$reply, $status] = $this->productSrvClient->getList(
(new ProductListRequest())
->setPage($param['page'] ?? 1)
->setPageSize($param['pageSize'] ?? 10)
);
if ($status != StatusCode::OK) {
return [
"code" => 1,
"message" => $reply ?? 'fail'
];
}
$temp = [];
/**
* @var ProductListReply $reply
* @var Product $item
*/
foreach ($reply->getList() as $item) {
$temp[] = json_decode($item->serializeToJsonString(),true); //懒人模式
}
return [
"code" => 0,
"message" => 'ok',
"data" => [
"total" => $reply->getTotal(),
"list" => $temp
]
];
}
}
3、配置路由
修改 config/routes.php 加入
Router::addGroup("/product", function () {
Router::post("/create", [\App\Controller\ProductController::class, 'create']);
Router::get("/list", [\App\Controller\ProductController::class, 'list']);
});
4、启动并访问
在 mall-api 根目录中执行
php bin/hyperf.php start
看到 [INFO] HTTP Server listening at 0.0.0.0:9501
即启动成功。
我们通过postman访问 看看。
第一次会相对比较慢,因为需要获取grpc连接客户端。
再次试下 访问 127.0.0.1:9501/product/list 会发现速度变快啦
总结
可以发现,我们并无配置 product服务地址,但插件自动帮我们在nacos中发现并使用了服务地址。我们把 mall-service 关闭,再访问看看
[ERROR] Get Node[mall] From nacos[round-robin] Fail! Because:Cannot select any node from load balancer.
程序就会提示我们,无节点可访问。感兴趣的同学可以 把策略改成 加权轮询(weighted-round-robin),并且再 nacos 中设置权重试试。
本作品采用《CC 协议》,转载必须注明作者和本文链接
应该是grpc链接不上
导致这一步会出现http错误!
顺着走下来就走不下去了。奇怪了