typescript grpc server client 一问一答 简单工具类(亲测可用,带注释、测试类)
-
工具类结构
-
目录结构
-
package.json 依赖
主要是proto-loader grpc 缺了啥补上啥把
"dependencies": {
"@grpc/proto-loader": "^0.6.1",
"@nestjs/common": "^7.6.15",
"@nestjs/config": "^0.6.3",
"@nestjs/core": "^7.6.15",
"@nestjs/microservices": "^7.6.15",
"@nestjs/mongoose": "^7.2.4",
"@nestjs/platform-express": "^7.6.15",
"@nestjs/schedule": "^0.4.3",
"@nestjs/swagger": "^4.8.0",
"@types/cron": "^1.7.2",
"class-transformer": "^0.4.0",
"class-validator": "^0.13.1",
"cron": "^1.8.2",
"dayjs": "^1.10.4",
"grpc": "^1.24.6",
"md5": "^2.3.0",
"mongoose": "^5.12.3",
"nest-winston": "^1.4.0",
"nuid": "^1.1.4",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^6.6.6",
"schedule": "^0.5.0",
"swagger-ui-express": "^4.1.6",
"winston": "^3.3.3",
"winston-daily-rotate-file": "^4.5.1"
},
"devDependencies": {
"@nestjs/cli": "^7.6.0",
"@nestjs/schematics": "^7.3.0",
"@nestjs/testing": "^7.6.15",
"@types/express": "^4.17.11",
"@types/jest": "^26.0.22",
"@types/logform": "^1.10.1",
"@types/node": "^14.14.36",
"@types/supertest": "^2.0.10",
"@types/winston": "^2.4.4",
"@typescript-eslint/eslint-plugin": "^4.19.0",
"@typescript-eslint/parser": "^4.19.0",
"eslint": "^7.22.0",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-prettier": "^3.3.1",
"jest": "^26.6.3",
"prettier": "^2.2.1",
"supertest": "^6.1.3",
"ts-jest": "^26.5.4",
"ts-loader": "^8.0.18",
"ts-node": "^9.1.1",
"tsconfig-paths": "^3.9.0",
"typescript": "^4.2.3"
}
- 工具类代码:GrpcUtil
const path = require('path');
const grpc = require('grpc');
export class GrpcUtil {
/**
* 返回的client直接调用方法传入参数例如,client.hello(requestObj,function(err,res){})
* @param protoPath proto文件的相对路径地址(当前路径为GrpcUtil类所在的路径)
* @param ip grpc服务器IP地址
* @param port grpc服务器端口
* @param packageName proto文件里的package
* @param serviceName proto文件里的service
*/
static getClient(protoPath:string, ip:string, port:number, packageName:string, serviceName:string){
const PROTO_PATH = path.join(__dirname,protoPath);
const protoLoader = require('@grpc/proto-loader');
const packageDefinition = protoLoader.loadSync(
PROTO_PATH,
{
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
}
);
const protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
const packageObj = protoDescriptor[packageName];
// 客户端
const client = new packageObj[serviceName](
ip+':'+port,
grpc.credentials.createInsecure()
);
return client
}
/**
* 关闭客户端
* @param client
*/
static closeClient(client){
if (client){
try {
client.close()
}catch (e) {
}
}
}
/**
* 启动grpc服务端
* @param protoPath proto文件的相对路径地址(当前路径为GrpcUtil类所在的路径)
* @param ip grpc服务器IP地址
* @param port grpc服务器端口
* @param packageName proto文件里的package
* @param serviceName proto文件里的service
* @param serviceImpl proto里定义的rpc函数的实现,例如hello函数的实现 {hello:(requestObj,callback)=>{console.log(requestObj.request);callback(null,'hi')}}
*/
static startServer(protoPath:string, ip:string, port:number, packageName:string, serviceName:string,serviceImpl:object){
const PROTO_PATH = path.join(__dirname,protoPath);
const protoLoader = require('@grpc/proto-loader');
const packageDefinition = protoLoader.loadSync(
PROTO_PATH,
{
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
}
);
const protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
const packageObj = protoDescriptor[packageName];
// 服务端
const server = new grpc.Server();
server.addService(
packageObj[serviceName].service,
serviceImpl
);
server.bind(ip+':'+port, grpc.ServerCredentials.createInsecure());
server.start();
return server
}
/**
* 关闭服务器
* @param server
*/
static closeServer(server){
if (server){
try {
server.close()
}catch (e) {
}
}
}
}
- 测试类
import {GrpcUtil} from "./GrpcUtil";
enum CodeType {
CodeType_ZERO,
SUCCESS,
FAILED
}
export class GrpcUtilTest {
static test(){
const Consts = {
serviceName : 'strategy.instances',
protoPath : './MarketData.proto',
ip:'192.168.0.140',
port:5000,
packageName : 'market_data_collector',
grpcServiceName : 'MarketDataService'
}
/**
* 注意 localhost 和 自己IP192.168.0.140是不同的,不要服务器和客户端地址不一样!!!会连不上
*/
let server = GrpcUtil.startServer(Consts.protoPath,Consts.ip,Consts.port,Consts.packageName,Consts.grpcServiceName,{
loadStrategyInstance:(request,callback)=>{
console.log('服务器收到请求');
console.log(request.request);
callback(null,{code:CodeType.SUCCESS,msg:'我是服务端,我收到了你的消息'})
}
})
let client = GrpcUtil.getClient(Consts.protoPath,Consts.ip,Consts.port,Consts.packageName,Consts.grpcServiceName)
client.loadStrategyInstance({id:'hhhhh'},(err,res)=>{
if (err){
console.log(err);
}
console.log('客户端收到结果');
console.log(res);
})
}
}
- 测试使用到的proto文件
我这边src->grpc下的proto文件是不会自动复制到dist目录去的,所以我是手动复制过去的,复制一次就行了,修改的时候都再手动覆盖过去
-
运行测试
以开发模式运行项目
-
测试结果
本文来自博客园,作者:HumorChen99,转载请注明原文链接:https://www.cnblogs.com/HumorChen/p/18039617