Skip to content
文档
开始使用

Get Started

在此之前,我希望你对gRPCprorobuf有所了解,这是最好的,当然,也可以通过这里来熟悉。 在这里我们将以一个简单例子来进行快速入门,分为四个步骤,分别是项目初始化,加载 proto,实现服务端和实现客户端。

💡

通过访问与阅读来进一步了解: gRPC & proto3

项目初始化

创建项目

创建 demo 项目并进入:

Terminal
mkdir demo && cd demo

初始化和安装依赖

Terminal
npm init -y
npm i grpcity
⚠️

注意: 我们需要在package.json里补上"type": "module",用于激活 ESM。

项目目录

我们需要创建一系列的目录和文件,最终项目目录与文件结构如下,其中高亮部分是需要我们手动提前创建:

Terminal
.
├── client.js
├── loader.js
├── package-lock.json
├── package.json
├── proto
   └── helloworld
       ├── model
   └── message.proto
       └── service.proto
└── server.js

加载 proto

定义 proto

我们定义两个 service,分别是 GreeterHellor,同时把 message 拆分到 model 里。

service.proto输入如下内容:

./proto/helloworld/service.proto
syntax = "proto3";
 
package helloworld;
 
import "helloworld/model/message.proto";
 
service Greeter {
  rpc SayGreet(HelloRequest) returns (HelloReply) {}
}
 
service Hellor {
  rpc SayHello(HelloRequest) returns (HelloReply) {}
}
 

message.proto输入如下内容:

./proto/helloworld/model/message.proto
syntax = "proto3";
 
package helloworld.model;
 
message HelloRequest {
  string name = 1;
}
 
message HelloReply {
  string message   = 1;
  int32 count = 2;
}

实现 loader

./loader.js输入如下内容:

./loader.js
import { ProtoLoader } from 'grpcity'
import path from 'node:path'
 
// __dirname for esm
import { fileURLToPath } from 'node:url'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
 
export default new ProtoLoader({
    location: path.join(__dirname, './proto'),
    files: [
        'helloworld/service.proto'
    ]
})
💡

ProtoLoaderlocationfiles含义分别表示 proto 目录和 service proto 文件。

至此,我们完成了 proto 文件的加载工作,并得到了loader.js。 这样我们就可以随处引入该文件,并支持我们去开发实现客户端或实现服务端。

实现服务端

这里的所有步骤将会在./server.js文件里进行。

导入 loader

./server.js
import loader from "./loader.js"

实现 Greeter

创建Greeter,并实现sayGreet方法:

./server.js
class Greeter {
    constructor() {
        this.count = 0
    }
 
    async sayGreet(call) {
        const { name } = call.request
        this.count++
        return {
            message: `hello ${name || "world"} by Greeter`,
            count: this.count
        }
    }
}

实现 Hellor

继续用同样的方式实现Hellor

./server.js
class Hellor {
    async sayHello(call) {
        const { name } = call.request
        return { message: `hello ${name || "world"} by Hellor` }
    }
}

绑定和启动

./server.js
const start = async (addr) => {
    // loader 初始化
    await loader.init()
 
    // server 初始化并获取实例
    const server = await loader.initServer()
 
    // 类方法与 service 进行绑定
    server.add('helloworld.Greeter', new Greeter())
    server.add('helloworld.Hellor', new Hellor())
 
    // 监听
    await server.listen(addr)
    console.log('helloworld server is started: ', addr)
}
 
// 启动
start('127.0.0.1:9098')

实现客户端

导入 loader

./client.js
import loader from "./loader.js"

获取客户端

创建 start 方法,完成获取客户端。

./client.js
const start = async (addr) => {
    await loader.init()
 
    const clients = await loader.initClients({
        services: {
            'helloworld.Greeter': addr,
            'helloworld.Hellor': addr
        }
    })
}

调用和启动

我们接着在 start 方法里补充客户端调用服务端的逻辑,并打印调用结果。

./client.js
const start = async (addr) => {
 
    // ...
    // loader init
    // clients init
    // ....
 
    // greeter client
    const greeterClient = clients.get('helloworld.Greeter')
    const greeterResult = await greeterClient.sayGreet({ name: 'grpcity' })
    console.log('greeterClient.sayGreet', greeterResult.response)
 
    // hellor client
    const hellorClient = clients.get('helloworld.Hellor')
    const hellorResult = await hellorClient.sayHello({ name: 'grpcity' })
    console.log('hellorClient.sayHello', hellorResult.response)
}
 
// 执行
start('127.0.0.1:9098')
💡

client发起调用后收到的结果包含了四个值,分别是statuspeermetadataresponse。在这里,我们只需要打印出response即可。

联调

我们需要两个终端窗口,分别用于执行服务端和客户端。

启动服务端

Terminal
node ./server.js
helloworld server is started:  127.0.0.1:9098

启动后,我们的客户端就可以连上相应的地址。

启动客户端

启动客户端,与服务端进行建联,并执行调用。在这里,我们会执行两次客户端。

第一次执行结果如下:

Terminal
node ./client.js
greeterClient.sayGreet { message: 'hello grpcity by Greeter', count: 1 }
hellorClient.sayHello { message: 'hello grpcity by Hellor' }

第二次执行结果如下:

Terminal
node ./client.js
greeterClient.sayGreet { message: 'hello grpcity by Greeter', count: 2 }
hellorClient.sayHello { message: 'hello grpcity by Hellor' }

我们能看到两次结果都是正常返回,其中sayGreet中的count,在第二次执行后累加为2, 符合预期,也说明这次客户端调用服务端的闭环完成了。

快速入门教程就此结束了,是不是感到简单和易用。如果需要更多了解,欢迎去往使用指南进行更多了解。

本篇的代码,将存放于 GitHub 上,欢迎访问。