javascript下grpc使用
2025-03-09 14:51:00protobuf介绍
//notice.proto
syntax="proto3";//使用proto3语法
package notice;//类似命名空间,一个proto文件只允许一个package
//message定义结构体
message Request{
required string accout=1;//required表示必须有值,'='表示第几个参数
string password=2;
repeated int32 array=3;//repeated类似数组定义,表示int32[]
optional int32 code;//optional 表示参数可以为空
}
message Response{
string name=1;
int32 age=2;
repeated string accounts=3;
}
message RequestFile{
string filename=1;
}
message ResponseFile{
string content=1;
}
//标准类型int32, int64, float, double, bool, string, bytes
//enum类型
enum Option{
VALUE1=0;
VALUE2=1;
}
//notice2.proto
import "./notice.proto"//导入其他proto文件
//服务类型
service Greeter{
rpc sayHello (Request) returns (Response);
//js中函数声明是function sayHello(call,callback);
//call.request是上述Request结构
//callback声明为(err,response)=>{};response是上述声明Response结构
}
流式rpc
客户机流式(发多个收一个)
rpc sayHelloStream (stream RequestFile) returns (ResponseFile);
//stream代表客户机发送多个Request
//上述js服务机代码片段(服务机返回数据不是流式)
function sayHelloStream(call,callback){
let data=[];
call.on('data',(request)=>{
data.push(request.filename);
});
call.on('end',()=>{
callback(null,{key:'其他属性'});
console.log('消息已回传');
});
call.on('error',(err)=>{});
}
//######################################
//客户机片段(客户机发送数据是流式)
let call=client.sayHelloStream((err,response)=>{});
call.write({'Request结构体'});
call.write({'Request结构体'});//可以多次write,流式发送
call.end();
服务机流式(发一个收多个)
rpc sayHelloStream (RequestFile) returns (stream ResponseFile);
//上述js服务机代码片段(服务机返回数据是流式)
function sayHelloStream(call){
//...一段检测要什么文件
const readStream = fs.createReadStream(call.request.filename, 'utf8');
readStream.on('data',(data)=>{
call.write({content:data});//这里假设了一个Response
});
readStream.on('end',()=>{
console.log('读完了');
call.end();//write方写完会启动接收方的end事件
});
readStream.on('error',(err)=>{
console.log('错了');
});
}
//######################################
//客户机片段(客户机接收数据是流式)
let call=client.sayHelloStream({filename:'xxx文件'});
call.on('data',(response)=>{
fs.appendFileSync('xxx文件',response.content,'utf-8');
});
call.on('end',()=>{
//读完了
});
call.on('error',(err)=>{//错了
});
双流式(多发多收)
rpc sayHelloStream (RequestFile) returns (stream ResponseFile);
//上述js服务机代码片段(服务机返回数据是流式)
function sayHelloStream(call){
call.on('data',(request)=>{
const readStream = fs.createReadStream(call.request.filename, 'utf8');
readStream.on('data',(data)=>{
call.write({content:data});
});
readStream.on('end',()=>{
console.log('读完了');
call.end();
});
readStream.on('error',(err)=>{
console.log('错了');
});
});
call.on('end',()=>{
call.end();
});
call.on('error',(err)=>{
});
}
//######################################
//客户机片段(客户机接收数据是流式)
let call=client.sayHelloStream();
call.on('data',(response)=>{
fs.appendFileSync('xxx文件',response.content,'utf-8');
});
call.on('end',()=>{
//读完了
});
call.on('error',(err)=>{//错了
});
call.write({filename:'xxx'});
call.write({filename:'xxx2'});
call.end();
Js grpc的使用
解析proto文件
//导入模块@grpc/grpc-js、@grpc/proto-loader
const grpc=require('@grpc/grpc-js');
const protoloader=require("@grpc/proto-loader");
//导入文件
const packageDefinition = protoloader.loadSync('文件.proto',{
keepCase:true,//保持.proto中字段名原样,否则用驼峰式
longs: String,//如何处理int64或uint64
enums: String,//如何处理枚举类型
defaults: true,//是否给字段默认值
oneofs: true,
/*
* message xxx{
* oneofs xxx2{
* int32 a=1;
* }
* }
* true 解析为{xxx2:{a:0}}
* false 解析为{a:0}
*/
includeDirs:['路径1','路径2'],//指定proto文件搜索路径
array: true,//true给repeated字段强制生产数组(只有一个值也是数组)
json:true//将message解析为json格式
});
//导入package
const package=grpc.loadPackageDefinition(packageDefinition).包名;
//#######################################################################
//实现函数,上节介绍过流式实现
function SayHello(call,callback){
}
//服务定义server.js
let server=new grpc.Server();
server.addService(package.服务名.service,{
//函数实现,比如sayHello:sayHello
});//服务名就是proto中有service关键字定义的东西
//启动服务
server.bindAsync(
"0.0.0.0:50051",//服务端监听所有网络接口
grpc.ServerCredentials.createInsecure(),//安全验证
()=>{
console.log("服务启动")
}//服务启动后回调
);
//#####################################################################
//客户机直接调用
let client=new package.服务名(
'服务机IP:端口',
grpc.credentials.createInsecure()//安全验证
);
client.sayHello({'request结构'},(err,reaponse)=>{});//本地调用远程接口
以上就是基本使用