Nodejs开发grpc的实例代码

 更新时间:2024年10月16日 09:44:30   作者:mazhongjia  
Nodejs开发grpc包含静态和动态两种代码生成方式,静态代码生成需要提前通过.proto文件编译生成JS源码,而动态代码生成则是在运行时指定IDL文件位置,实时生成源码,两者各有优缺点,本文给大家介绍Nodejs开发grpc的实例代码,感兴趣的朋友一起看看吧

nodejs开发grpc示例

Nodejs开发grpc有两种方式(与其他语言开发方式不同)

  • 静态代码生成:与传统方式一样,提前编译生成好js源码,开发时就可以应用生成js文件中源码。
  • 动态代码生成:不需要提前由.proto文件(IDL文件)生成js代码,而是通过提前指定好IDL文件的位置,运行时再生成对应的源码文件。

哪个好,哪个不好?没有明确规则,但是一个最佳实践:要么全部动态生成、要么全部静态生成,不然容易错乱。

开发nodejs,工程路径没有严格要求,这里在工程根目录下:

  • 创建app文件存放我们开发的js源码
  • 创建proto文件存放IDL文件
  • 由于nodejs是异步框架,所以编写nodejs代码绝大多数都是通过回调、通知、事件的方式获取对端的响应

一、动态代码生成

可见,代码中仅仅指定了IDL文件的路径,通过对应的gprc的load方法加载这个文件,全程没有用到grpc的编译工具生成相关代码。

工程结构:

这里是一个grpc的nodejs客户端与服务端实现,首先是服务端代码

//定义一个常量指定proto文件路径
var PROTO_FILE_PATH = 'E:\\01.study\\36.nodejs\\workspace\\grpc-demo\\proto\\Student.proto';
//引入GRPC库
var grpc = require('grpc');
//找到我们在IDL文件中定义的service:StudentService
var grpcService = grpc.load(PROTO_FILE_PATH).com.mzj.netty.ssy._08_grpc;
//定义服务端
var server = new grpc.Server();
server.addService(grpcService.StudentService.service,{
    //添加测试的rpc方法,服务名:服务对应调用方法
    getRealNameByUsername: getRealNameByUsername1,
    // 添加其他rpc方法
    getStudentsByAge: getStudentsByAge1,
    getStudentsWrapperByAges: getStudentsWrapperByAges1,
    biTalk: biTalk1,
})
//绑定端口,并设置不是用ssl安全加密
server.bind('localhost:8899',grpc.ServerCredentials.createInsecure());
//启动服务器
server.start();
//实现rpc服务调用处理函数:参数1call:请求对象,参数2callback:回调函数
function getRealNameByUsername1(call,callback) {
    console.log("username : " + call.request.username);//打印请求对象
    /**
     * 定义回调函数
     */
    callback(null,{realname: 'mazhongjia'});//参数1:错误对象,这里不进行设置,参数2:返回给客户端的结果对象,这里的属性名对应IDL中声明的属性名
}
function getStudentsByAge1(){
}
function getStudentsWrapperByAges1(){
}
function biTalk1(){
}
 

然后是客户端代码:

//--------------动态代码生成的方式:--------------
//1、定义grpc的IDL文件位置
var PROTO_FILE_PATH = 'E:\\01.study\\36.nodejs\\workspace\\grpc-demo\\proto\\Student.proto';
//2、引入grpc库,nodejs中,引入库用require方法
var grpc = require('grpc');
//3、定义grpc服务
//找到我们在IDL文件中定义的service:StudentService
var grpcService = grpc.load(PROTO_FILE_PATH).com.mzj.netty.ssy._08_grpc;
//4、定义nodejs客户端
var client = new grpcService.StudentService('localhost:8899',grpc.credentials.createInsecure());
//grpc.credentials.createInsecure():创建的是一个不安全的、不是用ssl证书加密的通道,与java如下代码等价:
//.usePlaintext(true).
//调用rpc方法,其中方法首字母转小写
client.getRealNameByUsername({username:'lisi'},function (error,respData) {
    console.log(respData);
})
 

grpc的IDL文件:

syntax = "proto3";
package com.mzj.netty.ssy._08_grpc;
option java_package = "com.mzj.netty.ssy._08_grpc";
option java_outer_classname = "StudentProto";
option java_multiple_files = true;
service StudentService{
    //gRpc支持的四种调用形式示例:
    rpc GetRealNameByUsername(MyRequest) returns (MyResponse){}//种类1:普通输入参数与返回值
    rpc GetStudentsByAge(StudentRequest) returns (stream StudentResponse){}//种类2:服务端rpc方法返回值是stream形式,参数是普通对象
    rpc GetStudentsWrapperByAges(stream StudentRequest) returns (StudentResponseList){}//种类3:客户端输入参数是stream形式,返回是一个普通对象
    rpc BiTalk(stream StreamRequest) returns (stream StreamResponse){}//种类4:双向的流式的数据传递(客户端发送请求/服务端返回结果都是流式)
    //从IDL的定义上,四种调用形式区别体现在rpc定义时方法参数、返回值的message前面是否有stream关键字
    //rpc方法的参数与返回值类型都是IDL中定义的message类型,而不能是string、int32等变量类型,这一点跟thrift不同,即使只有一个属性,也得定义成message
}
message MyRequest{
    string username = 1;
}
message MyResponse{
    string realname = 2;
}
message StudentRequest{
    int32 age = 1;
}
message StudentResponse{
    string name = 1;
    int32 age = 2;
    string city = 3;
}
message StudentResponseList{
    //protobuf中集合用repeated表示
    repeated StudentResponse studentResponse = 1;//repeated表示集合类型,这里表示服务器端向客户端返回的是一个集合类型,集合中元素是StudentResponse
}
message StreamRequest{
    string request_info = 1;
}
message StreamResponse{
    string response_info = 1;
}

分别运行服务端、客户端代码。

二、静态代码生成

1、说明:通过grpc编译器protoc预先生成js源码,然后编码过程中显示调用。

2、具体操作方式:按照官网示例

https://github.com/grpc/grpc/tree/v1.4.x/examples/node/static_codegen

下面内容参考的是上面网址的README.md文件

步骤1:安装grpc-tools,通过nodejs的npm包管理工具按照grpc-tools插件

npm install -g grpc-tools

步骤2:通过编译器生成对应nodejs源码:

下面是readme文件中原始命令,需要进行修改

grpc_tools_node_protoc --js_out=import_style=commonjs,binary:../node/static_codegen/ --grpc_out=../node/static_codegen --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` helloworld.proto

修改后实际执行的为:

grpc_tools_node_protoc --js_out=import_style=commonjs,binary:static_codegen/ --grpc_out=static_codegen --plugin=protoc-gen-grpc=/c/Users/mzj/AppData/Roaming/npm/grpc_tools_node_protoc_plugin.cmd proto/Student.proto

其中两个路径分别是生成的消息源码路径和grpc通信源码路径,我们修改成生成到相同的路径

其中/c/Users/mzj/AppData/Roaming/npm/grpc_tools_node_protoc_plugin是通过执行原始命令中which grpc_tools_node_protoc_plugin得到的,但是后面需要加上.cmd:

执行后出错:

提示没有这个目录,手工创建后再执行,则OK

生成代码如下:

其中这两个文件:Student_pb.js是消息相关源码,Student_grpc_pb.js是grpc相关通信代码(与java生成源码类似,也是消息+grpc通信两部分)

编写客户端代码:

//1、定义service,service位于Student_grpc_pb.js中
var service = require('../static_codegen/proto/Student_grpc_pb.js');
//2、定义消息
var message = require('../static_codegen/proto/Student_pb.js');
//3、引入grpc库
var grpc = require('grpc');
//4、定义客户端
var client = new service.StudentServiceClient('localhost:8899',grpc.credentials.createInsecure());
//5、定义请求message(与动态生成方式不同)
var request = new message.MyRequest();
request.setUsername('huna');
//6、调用rpc方法
client.getRealNameByUsername(request,function (error,respData) {
    //静态调用方式是以方法调用的方式获取返回结果,因为rpc的返回值在编译期可见,而动态方式rpc返回值编辑期不可见、是通过属性的方式获取结果
    console.log(respData.getRealname());//打印返回结果
})

测试:启动动态代码生成编写的服务端、启动静态代码生成的客户端。

静态代码生成方式编写的服务端:

总结动态与静态代码生成方式优缺点: 静态与动态方式使用场景,到底使用哪种(视频31_30分钟)动态方式好处:不需要预先生成源码文件动态方式缺陷:编写代码阶段无法获取具体有哪些属性,只能自己保证编写代码属性的正确性,无法在编译期保证正确性,同时可读性不好静态方式好处:每一个对象有什么方法,编写代码阶段都能看到,代码可读性好静态方式缺点:较动态方式麻烦我推荐使用静态代码生成的方式:因为代码编写过程中一些代码编写提示与可读性更重要,而自动生成代码可以通过编写脚步实现自动化。

到此这篇关于Nodejs开发grpc的文章就介绍到这了,更多相关Nodejs开发grpc内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • nodejs中函数的调用实例详解

    nodejs中函数的调用实例详解

    本文通过实例代码给大家介绍了nodejs函数的调用,代码简单易懂,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-10-10
  • node.js利用redis数据库缓存数据的方法

    node.js利用redis数据库缓存数据的方法

    Redis数据库采用极简的设计思想,最新版的源码包还不到2Mb。其在使用上也有别于一般的数据库。下面这篇文章就来给大家介绍了node.js利用redis数据库缓存数据的方法,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-03-03
  • 在Node.js中实现文件复制的方法和实例

    在Node.js中实现文件复制的方法和实例

    这篇文章主要介绍了在Node.js中实现文件复制的方法和实例,使用FS模块实现,需要的朋友可以参考下
    2014-06-06
  • 使用Node.js实现HTTP 206内容分片的教程

    使用Node.js实现HTTP 206内容分片的教程

    这篇文章主要介绍了使用Node.js实现HTTP 206内容分片的教程,Node.js是一款用于服务器端的JavaScript框架,需要的朋友可以参考下
    2015-06-06
  • Node.js查询MySQL并返回结果集给客户端的全过程

    Node.js查询MySQL并返回结果集给客户端的全过程

    nodejs最大的优势也是大家用着最为难以理解的一点,就是它的异步功能,它几乎所有的io操作都是异步的,这也就导致很多人不理解也用不习惯,下面这篇文章主要给大家介绍了关于Node.js查询MySQL并返回结果集给客户端的相关资料,需要的朋友可以参考下
    2022-12-12
  • Node.js自定义对象事件的监听与发射

    Node.js自定义对象事件的监听与发射

    这篇文章介绍了Node.js自定义对象事件监听与发射的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • Node.js安装详细步骤教程(Windows版)详解

    Node.js安装详细步骤教程(Windows版)详解

    这篇文章主要介绍了Node.js安装详细步骤教程(Windows版),本文图文并茂给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-09-09
  • Express实现Session身份认证的示例代码

    Express实现Session身份认证的示例代码

    本文主要介绍了Express实现Session身份认证的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • 如何通过node.js来写接口详解

    如何通过node.js来写接口详解

    最近研究了一下nodejs写接口,发现接口并不难写,这篇文章主要给大家介绍了关于如何通过node.js来写接口的相关资料,文中通过实例代码和图文介绍的非常详细,需要的朋友可以参考下
    2022-09-09
  • Node.js模块封装及使用方法

    Node.js模块封装及使用方法

    这篇文章主要为大家详细介绍了Node.js模块封装及使用方法,感兴趣的朋友可以参考一下
    2016-03-03

最新评论