hetao29 / php-grpc-server-protobuf
使用 protobuf 的 php grpc 服务器框架,不使用任何第三方库。
1.7.5
2024-04-24 04:04 UTC
Requires
- ext-grpc: *
- ext-swoole: *
- google/protobuf: *
- grpc/grpc: *
README
使用 protobuf 的 php grpc 服务器框架,不使用任何第三方库或使用 Swoole。支持 protobuf 和 json 请求。
架构
与 nginx & php-fpm 一起使用的方式(仅支持 php 客户端和 http json 请求)
- gRPC 客户端 > nginx > php-fpm > 此框架 > 自定义服务 > protobuf 二进制响应
- http/https json 请求(content-type:application/json) > nginx > php-fpm > 此框架 > 自定义服务 > json 响应
与 swoole 一起使用的方式(所有 gRPC 客户端和 http json 请求)
- gRPC 客户端 > Swoole > 此框架 > 自定义服务 > protobuf 二进制响应
- http/https json 请求(content-type:application/json) > Swoole > 此框架 > 自定义服务 > json 响应
使用方法
- 使用 composer 安装
composer require "hetao29/php-grpc-server-protobuf:dev-main"
- 在 php 文件中使用,如 samples/www/index.php(php-fpm 模式)
<?php define("ROOT", dirname(__FILE__)."/../"); define("ROOT_LIBS", ROOT."/libs"); define("ROOT_APP", ROOT."/app"); define("ROOT_PROTO_GENERATED", ROOT."/proto_generated"); require_once(ROOT_LIBS."/vendor/autoload.php"); spl_autoload_register(function($class){ $root = ROOT_PROTO_GENERATED."/".str_replace("\\","/",$class).".php"; if(is_file($root)){ require_once($root); } }); spl_autoload_register(function($class){ $root = ROOT_APP."/".str_replace("\\","/",$class).".php"; if(is_file($root)){ require_once($root); } }); try{ $content_type = (isset($_SERVER['HTTP_CONTENT_TYPE']) && $_SERVER['HTTP_CONTENT_TYPE']=='application/json') ? 'json' : null; //json | null (default) if(($r=GRpcServer::run(null,null,$content_type))!==false){ echo($r); } }catch(Exception $e){ print_r($e); }
- 或 swoole 服务器
<?php require __DIR__ . '/../libs/vendor/autoload.php'; define("ROOT", __DIR__."/../"); define("ROOT_APP", __DIR__."/../app"); define("ROOT_PROTO_GENERATED", __DIR__."/../proto_generated/"); spl_autoload_register(function($class){ $root = ROOT_PROTO_GENERATED."/".str_replace("\\","/",$class).".php"; if(is_file($root)){ require_once($root); } }); spl_autoload_register(function($class){ $root = ROOT_APP."/".str_replace("\\","/",$class).".php"; if(is_file($root)){ require_once($root); } }); $http = new Swoole\Http\Server('0.0.0.0', 50000, SWOOLE_BASE); $http->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) use ($http) { $content_type = (isset($request->header['content-type']) && $request->header['content-type']=='application/json') ? 'json' : null; //json | null (default) if($content_type=="json"){ $response->header('content-type', 'application/json'); }else{ $response->header('content-type', 'application/grpc'); } try{ if(($r=GRpcServer::run($request->server['request_uri'], $request->rawContent(), $content_type))!==false){ //echo($r); $response->header('trailer', 'grpc-status, grpc-message'); $trailer = [ "grpc-status" => "0", "grpc-message" => "" ]; foreach ($trailer as $trailer_name => $trailer_value) { $response->trailer($trailer_name, $trailer_value); } $response->end($r); } }catch(Exception $e){ $response->header('trailer', 'grpc-status, grpc-message'); $trailer = [ "grpc-status" => $e->getCode(), "grpc-message" => $e->getMessage(), ]; foreach ($trailer as $trailer_name => $trailer_value) { $response->trailer($trailer_name, $trailer_value); } $response->end(); } }); $http->start();
编写应用程序服务
- 将 proto 和 genproto 转换为 php 文件
cd proto && make
- 在 services 目录中编写 gRPC 服务器,例如 helloworld
<?php namespace Test\Helloworld; class Greeter implements GreeterInterface{ /** */ public function SayHello(HelloRequest $request) : HelloReply{ $reply = new HelloReply(); $reply->setMessage("Hello2, ".$request->getName()."!"); return $reply; } }
- 配置 nginx 和 php-fpm
server {
listen 50010 http2; #with http2 is grpc protocol
#listen 50010; #without http2 is json protocol
root /data/server/;
location / {
if (!-e $request_filename){
rewrite ^/(.+?)$ /index.php last;
}
}
location ~ \.php$ {
fastcgi_param REMOTE_ADDR $http_x_real_ip;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
- 测试
# cli mode php client/hello.php # curl command (json request) # swoole (50000 port) curl -d '{"name":"xx"}' -v http://127.0.0.1:50000//Test.Helloworld.Greeter/SayHello -H "content-type:application/json" # nginx php-fpm (50010 port) curl -d '{"name":"xx"}' -v http://127.0.0.1:50010//Test.Helloworld.Greeter/SayHello -H "content-type:application/json" # or web browser