php作为客户端调用golang grpc服务(目前php无法用做grpc的服务端,但是作为客户端是没有问题的)
开发环境(本地):windows+docker(镜像:php:7.3-fpm-alpine)
框架:laravel 5.8
1、首先安装grpc服务,由于docker使用alpine镜像,所以直接使用apk add grpc可快速安装,安装后输入protoc --version看是否正常,源码编译安装由于需要下载github上面很多的第三方包导致非常慢,我的是一直无法安装;容器中也可以不安装,在本地开发机器上面安装(注意版本:最新版本3.14和3.15在本地windows上一直无法正常生成php文件,总是乱码,我使用的是3.12.2),然后生成php客户端文件之后直接放入项目中
2、安装php grpc扩展和protobuf扩展(尽量不要最新版本,在这里卡了好久,新版本一直无法安装成功,后来使用旧版本后成功安装)
docker-file:
&& pecl install grpc-1.26.0 \
&& docker-php-ext-enable grpc \
&& pecl install protobuf-3.10.0 \
&& docker-php-ext-enable protobuf
使用phpinfo查看是否正常安装了这两个扩展
3、项目文件composer.json中引入grpc和protobuf(在项目app下新增文件夹Grpc及Proto,用于存放proto文件和及转换后的php文件)
运行:composer install
4、编写proto文件
syntax = "proto3";
option go_package = ".;user";
package user;
//用户中心定义
service UserService {
//操作用户积分和余额
rpc ApiUser(ApiUserRequest) returns (Response) {
}
}
message ApiUserRequest {
int64 type = 1;
int64 uid = 2;
int64 num = 3;
string sign = 4;
}
//通用响应数据
message Response {
int64 code = 1;
string message = 2;
int64 time = 3;
map<string,string> data = 4;
}
将文件放入项目proto文件夹中,并在该文件夹下运行命令:
protoc --php_out=../Grpc/UserCenter --grpc_out=../Grpc/UserCenter --plugin=protoc-gen-grpc=/usr/bin/grpc_php_plugin userService.proto
会在Grpc/UserCenter下生成以下几个文件
注意:grpc_php_plugin插件,第一步安装完grpc后一般都会在/usr/bin中生成此文件,如果缺失可以更换命令:protoc --php_out=../Grpc/UserCenter userService.proto,但将无法生成UserServiceClient.php文件,不过客户端文件内容非常简单,可以自己参考以下编写
// GENERATED CODE -- DO NOT EDIT!
namespace User;
/**
* 用户中心定义
*/
class UserServiceClient extends \Grpc\BaseStub {
/**
* @param string $hostname hostname
* @param array $opts channel options
* @param \Grpc\Channel $channel (optional) re-use channel object
*/
public function __construct($hostname, $opts, $channel = null) {
parent::__construct($hostname, $opts, $channel);
}
/**
* 操作用户积分和余额
* @param \User\ApiUserRequest $argument input argument
* @param array $metadata metadata
* @param array $options call options
*/
public function ApiUser(\User\ApiUserRequest $argument,
$metadata = [], $options = []) {
return $this->_simpleRequest('/user.UserService/ApiUser',
$argument,
['\User\Response', 'decode'],
$metadata, $options);
}
}
5、最后在项目中调用客户端类
public function client(){
$client = new \User\UserServiceClient('192.168.10.41:16000',[
'credentials' => \Grpc\ChannelCredentials::createInsecure()
]);
$request = new \User\ApiUserRequest();
$request->setType(1);
$request->setUid(111);
$request->setNum(1341);
$request->setSign("asfasdf");
$get = $client->ApiUser($request)->wait();
list($reply,$status) = $get;
if ($status->code !== \Grpc\STATUS_OK) {
throw new \Exception($status->details,$status->code);
}
if($reply->getCode() != 200){
throw new \Exception($reply->getMessage(),$reply->getCode());
}
// getData返回的是MapField类,直接用dump是看不到具体结果的
foreach ($reply->getData() as $k=>$v){
dump($k."=>".$v);
}
// 也可使用以下方式获取具体键值内容
dump($reply->getData()->offsetGet("a"));
}
结果展示: