-
工具类结构
-
目录结构
-
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目录去的,所以我是手动复制过去的,复制一次就行了,修改的时候都再手动覆盖过去
-
运行测试
以开发模式运行项目 -
测试结果