遇到语焉不详的文档踩了一堆坑,示例有用但不多,还是记录一下免得以后忘了……
安装依赖
yarn add -D grpc-tools @grpc/grpc-js @grpc/proto-loader google-protobuf
编辑 proto 文件
仅供参考
syntax = "proto3";
package pb;
service PoolService {
rpc GetContents(Query) returns (Response);
}
message Content {
string content = 1;
int64 expire = 2;
}
message Query {
int64 count = 1;
}
message Response {
repeated Content data = 1;
}
静态生成
npx grpc_tools_node_protoc --js_out=import_style=es6,binary:. --grpc_out=. --proto_path=. mypb.proto
- 全部目录我都写了
.
,为的是生成在当前文件夹,未来再根据需要移到其他目录,所以这些值需要根据实际情况来填
ESM 支持
grpc-tools 对 esm 的支持属于是一言难尽,只能生成以后自己改了
- mypb_pb.js
- 将开头的
require
引入改成import
- 在末尾导出
proto.pb
(这个名字取决于前面填的包名)
- 将开头的
- mypb_grpc_pb.js
- 将开头的
require
引入改成import
- 在结尾的相关函数使用
export
导出
- 将开头的
// mypb_pb.js
/// begin
+import jspb from 'google-protobuf'
+var goog = jspb
/// end
+export default proto.pb
// mypb_grpc_pb.js
/// begin
-var grpc = require('grpc');
-var mypb_pb = require('./mypb_pb.js');
+import grpc from '@grpc/grpc-js'
+import mypb_pb from './mypb_pb.js'
/// end
-var PoolServiceService = exports.PoolServiceService = {
+export const PoolServiceService = {
getContents: {
path: '/pb.PoolService/GetContents',
requestStream: false,
responseStream: false,
requestType: mypb_pb.Query,
responseType: mypb_pb.Response,
requestSerialize: serialize_pb_Query,
requestDeserialize: deserialize_pb_Query,
responseSerialize: serialize_pb_Response,
responseDeserialize: deserialize_pb_Response,
},
};
-exports.PoolServiceClient = grpc.makeGenericClientConstructor(PoolServiceService);
+export const PoolServiceClient = grpc.makeGenericClientConstructor(PoolServiceService);
* 2024-06-18 补充
根据上面的 diff 文件,配合 GPT 写出了以下修改代码
#!/bin/bash
# the `package` from .proto file
PB_PACKAGENAME="pb"
npx grpc_tools_node_protoc --js_out=import_style=es6,binary:. --grpc_out=. --proto_path=. *.proto
# ends with _pb.js
for file in $(find . -maxdepth 1 -name "*_pb.js" ! -name "*_grpc_pb.js"); do
sed -i '1i import jspb from '\''google-protobuf'\''\nlet goog = jspb' "$file"
echo "export default proto.$PB_PACKAGENAME" >> "$file"
done
# ends with _grpc_pb.js
for file in *_grpc_pb.js; do
PREFIX=$(basename "$file" "_grpc_pb.js")
sed -i "s|var grpc = require('grpc');|import grpc from '@grpc/grpc-js'|g" "$file"
sed -i "s|var ${PREFIX}_pb = require('./${PREFIX}_pb.js');|import ${PREFIX}_pb from './${PREFIX}_pb.js'|g" "$file"
SERVICE_VAR=$(grep -oP "var \K\w+(?= = exports\.)" "$file")
sed -i "s|var $SERVICE_VAR = exports\.$SERVICE_VAR =|export const $SERVICE_VAR =|g" "$file"
sed -i "s|exports\.\(\w\+\) =|export const \1 =|g" "$file"
done
使用
import grpc from '@grpc/grpc-js'
import * as grpc_pb from 'mypb_grpc_pb.js'
import pb from 'mypb_pb.js'
const client = new grpc_pb.PoolService('localhost:50051', grpc.credentials.createInsecure())
let request = new pb.GetContents()
request.setCount(10)
client.getContents(request, (error, response) => {
if (error) {
console.error('Error:', error)
} else {
console.log('Response:', response)
}
})
杂项
- 发送请求时会直接使用环境变量里面的 http 代理
- 生成的文件里面莫名其妙的
goog
其实就是google-protobuf
- 没有服务端代码的原因是服务端是 Golang 写的,文档齐全配 GPT 三两下就弄好了
- 还有一些奇怪的细节我已经记不清楚了