gRPC的简单使用
chenlong-io opened this issue · 0 comments
gRPC 是谷歌开源的一套多语言 RPC 框架,用官网的一句话来概括就是:
A high-performance, open-source universal RPC framework
翻译过来就是:一个高性能、开源通用的 RPC 框架。gRPC 也是一个遵循server/client模型的框架
gRPC 使用
先安装 grpc 和 @grpc/proto-loader
yarn add grpc @grpc/proto-loader
由于 gRPC 使用谷歌特有的 Protocol Buffer,用于序列化结构化数据的自动化过程,只需要定义如何组织你的结构化数据一次,就可以使用 protoc 轻松的根据这个定义生成语言相关的源代码(支持多种语言),以便于读写结构化数据。
这里通过 @grpc/proto-loader 来解析 proto 文件
关于 protoc buffer ,可以参考 Protocol Buffer是什么? 这篇文章
定义 hello.proto
protoBuffer 目前有 2 和 3 两个版本,这里我们用版本 3
// 使用 proto3
syntax = "proto3";
// 定义包名
package helloworld;
// 定义Hello服务
service Hello {
// 定义 sayHello 方法
rpc sayHello (HelloReq) returns (HelloRes);
}
// 定义 sayHello 方法的传值
message HelloReq {
// 传入 name,1表示第一个参数
string name = 1;
// 传入 age,2表示第二个参数
int32 age = 2;
// 传入 job
string job = 3;
}
message HelloRes {
string message = 1;
}protobuf 书写较为严格,不要忘记分号。
需要注意的是,以 string name = 1;为例,这里的 1 表示第一个参数,其实在JSON格式里表示第一个 key ,比如:
message HelloReq {
// 传入 name,1表示第一个参数
string name = 1;
// 传入 age,2表示第二个参数
int32 age = 2;
}
// 对应的 JSON, 第一个 key 必须是 name ,第二个是 age
{
name: '',
age: 20
}Server
RPC 分为 Server 端和 Client 端,我们先写 Server 端代码
首先就是引入 grpc 和 @grpc/proto-loader,先使用 proto-loader 加载 proto 文件生成对应的 package,然后通过 grpc 加载这个包,并通过.helloworld来返回 helloword 这个包(对应的是 proto 文件里的 package helloworld;)
const grpc = require('grpc')
const protoLoader = require('@grpc/proto-loader')
const path = require('path')
// 加载 proto 文件并配置
const packageDefinition = protoLoader.loadSync(
path.resolve(__dirname, '../proto/hello.proto'),
{
// 保留现场大小写而不是转换为驼峰格式
keepCase: true,
// 长转换类型。有效值为String和Number(全局类型)。默认情况下将复制当前值,这是一个不安全的数字,如果不带{@link Long}且带有长库的话。
longs: String,
// 枚举值转换类型。唯一有效的值是`String`(全局类型)。默认情况下复制当前值,即数字ID。
enums: String,
// 在结果对象上设置默认值
defaults: true,
// 包括设置为当前字段名称的虚拟oneof属性(如果有的话)
oneofs: true
}
)
// 使用 grpc 加载包
const helloProto = grpc.loadPackageDefinition(packageDefinition).helloworld上面这部分仅仅是对 proto 文件的处理,由于 Server 端和 Client 都用同一份 proto,所以这部分代码是服务端和客户端都要用到的。
现在 proto 已经解析好了,我们接着上面的代码开始写一个服务:
// 创建 server
const server = new grpc.Server()
// 添加服务, 这里的服务名叫Hello
server.addService(helloProto.Hello.service, {
// 实现sayHello方法
sayHello
})
// sayHello 方法,call 用来获取请求信息,callback 用来向客户端返回信息
function sayHello(call, callback) {
try {
// 获取 name 和 age
const { name, age, job } = call.request
console.log('收到客户端传值:', name, age, job)
// 按 proto 约定传值,返回`我叫${name},年龄${age}`
callback && callback(null, { message: `我叫${name},年龄${age}` })
} catch (error) {
console.log('服务出错', error)
callback && callback(error)
}
}
// 异步启动
server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => {
server.start()
console.log('server start...')
})打开控制台,输入 node server/index.js运行该服务
Client
因为 Client 也需要解析 proto,上文已经有相关代码,这里只写 Client 余下的代码:
// 创建客户端
const client = new helloProto.Hello(
'localhost:50051',
grpc.credentials.createInsecure()
)
// 调用 sayHello 方法
client.sayHello({ name: '张三', age: 30, job: 'teacher' }, (err, response) => {
if (err) {
console.log(err)
return
}
const { message } = response
console.log(message)
})客户端就这么简单。
现在运行 node client/index.js
客户端调用 sayHello 方法,并传入{ name: '张三', age: 30, job: 'teacher' } ,服务端接收到参数后通过 sayHello 处理,并返回给客户端 我叫张三,年龄30
完整代码见:https://github.com/Vibing/node-grpc
至此,gRPC 一个简单的调用就完成了,就是这么简单。
