Laravel 整合 gRPC (ft. Node.js)
tags: PHP
Laravel
RPC
Node.js
Protocol buffer
category: Back-End
description: Laravel 整合 gRPC (ft. Node.js)
created_at: 2021/08/28 19:00:00
前言
很久沒有發新的文章了,這次把最近做到花很多時間的東西紀錄一下,避免之後要做又要花很多時間重來。
雖然說文件很多,但也相對很散,官方上跟 Github
上不見得同步,需要東串西串,PHP+gRPC 網路上也滿多都是2019年左右的資料,不見得動的起來,Laravel的話資料更是少。
題外話: 花很多時間有很大的原因是 純Windows不友善。
稍微描述一下: 官方github上有提供PHP範例原始碼,是已經經過 protoc 編譯過的,而php在compile的時候需要帶一個plugin才會產生client,而那個plugin只能在unix上build,windows雖然網路上有人提供.exe,但不是很敢使用。
所以這邊主要是 windows 上開發的解決方案,在 WSL 中只會安裝編譯需要的東西,並不會安裝PHP執行的套件(ex: extension)
事前準備
- Windows請啟用WSL(https://docs.microsoft.com/zh-tw/windows/wsl/install-win10)
- 去商店安裝 Ubuntu 20.04 LTS 版
- 裝好 Node.js
- 裝好 PHP (
應該不用多說) - 下載 PHP gRPC extension(https://pecl.php.net/package/grpc)
- 在php.ini啟用 (extension=php_grpc.dll)
準備開始
Laravel 專案有他自己的目錄結構,但是 protobuf 你要丟哪邊都可以,反正最後要經過 protoc 編譯,再讓 composer 去幫你做 autoload,所以路徑對的到就沒問題。
假設我建立資料夾在根目錄 /protobuf
- /protobuf
- /protos -> 放 .proto
- /compile -> 放編譯完的結果
建立 hello.proto
syntax = "proto3";
package hello;
// 定義 Request
message HelloRequest {
string name = 1;
}
// 定義 Response
message HelloResponse {
string message = 1;
}
// 定義 Server(Service) 提供的方法
service Hello {
rpc Hello (HelloRequest) returns (HelloResponse) {
}
}
進入到你的 WSL (ubuntu)
-
先更新套件來源
$ sudo apt update
-
安裝PHP
sudo add-apt-repository ppa:ondrej/php sudo apt -y install php8.0
-
安裝編譯相關套件
$ sudo apt -y install php8.0-dev autoconf automake libtool make gcc libz-dev cmake
-
clone官方github原始碼(假設這裡用1.39.0版)
$ git clone --recurse-submodules -b v1.39.0 https://github.com/grpc/grpc
-
編譯grpc_php_plugin
cd grpc mkdir -p cmake/build cd cmake/build cmake ../.. make protoc grpc_php_plugin
-
安裝 protobuf-compiler
$ sudo apt -y install protobuf-compiler
-
切到你的 Laravel 專案目錄
-
編譯 .proto
$ protoc --proto_path=protobuf/protos \ --php_out=protobuf/compile \ --grpc_out=protobuf/compile \ --plugin=protoc-gen-grpc={grpc_php_plugin path} \ hello.proto
{grpc_php_plugin path},如果你是在家目錄執行,上面的所有動作,應該會長得像
/home/{username}/grpc/cmake/build/grpc_php_plugin
回到你熟悉的編輯器
Client端 (Laravel)
-
安裝 grpc 與 protobuf 套件
$ composer require "grpc/grpc" "google/protobuf"
-
設定 composer.json 的 autoload
{ ... "autoload": { "psr-4": { "App\\": "app/", "Database\\Factories\\": "database/factories/", "Database\\Seeders\\": "database/seeders/", "Hello\\": "protobuf/compile/Hello", "GPBMetadata\\": "protobuf/compile/GPBMetadata" } }, ... }
-
重新生成 autoload files
$ composer dump-autoload
-
建立 Controller
$ php artisan make:controller MainController
-
貼上
<?php
namespace App\Http\Controllers;
use Hello\HelloClient;
use Hello\HelloRequest;
class MainController extends Controller
{
public function index() {
$host = 'localhost:50051';
$client = new HelloClient($host, [
'credentials' => \Grpc\ChannelCredentials::createInsecure(),
]);
$request = new HelloRequest();
$request->setName('test');
$call = $client->Hello($request);
list($response, $status) = $call->wait();
dd($response, $status);
}
}
- 修改路由
use App\Http\Controllers\MainController; Route::get('/', [MainController::class, 'index']);
Server端 (Node.js)
-
安裝 grpc_tools (假設上面的 protoc 已經裝好)
$ npm install -g grpc-tools
-
編譯
$ grpc_tools_node_protoc --proto_path=protobuf/protos --js_out=import_style=commonjs,binary:protobuf/compile --grpc_out=grpc_js:protobuf/compile hello.proto
-
安裝 @grpc/grpc-js 與 google-protobuf
$ npm install @grpc/grpc-js google-protobuf
-
建立 hello_server.js
const grpc = require('@grpc/grpc-js');
const messages = require('./protobuf/compile/hello_pb');
const services = require('./protobuf/compile/hello_grpc_pb');
function hello(call, callback) {
const reply = new messages.HelloResponse();
reply.setMessage('Hello ' + call.request.getName());
callback(null, reply);
}
const server = new grpc.Server();
server.addService(services.HelloService, { hello });
server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => {
server.start();
});
啟動 Laravel server
$ php artisan serv
之後到你的瀏覽器上面看,應該就會看到結果了!
總結
步驟真的是滿多的,而且第一次用找了一堆資料很零散真的花了很多時間,加上一開始我是打算全程用純windows就好,結果踩到一堆坑,後來只好加上WSL輔助。