Skip to content
文档
Client

Client

Client 是gRPCity的核心功能之一,主要是提供获取 service,并进行 rpc 调用。

初始化

const clients = await loader.initClients({ services, channelOptions, credentials })

参数说明:

  • services: 必须,{ [service name]: address }
    • [service name]: 含包名的 service 名称;
    • address: 服务端通信地址,有两种格式支持,如:host:port或者{ host, port }
  • channelOptions: 可选,通信配置规则;
  • credentials: 可选,客户端端证书;

完整示例如下:

const credentials = loader.makeCredentials(rootCerts, privateKey, certChain, verifyOptions)
const clients = await loader.initClients({
    services: {
        'dev.path.to.serviceA': 'domain.local:9099',
        'path.to.serviceB': {
            host: '192.168.32.111',
            port: 10099
        }
    },
    channelOptions,
    credentials,
})

添加中间件

clients.use()提供了call method前后处理的中间件能力,更多详情查看 Middleware 指南

// implementation 中间件支持
// 逐个添加
clients.use(f1)
clients.use(f2)
clients.use(f3)
// 传入多个参数添加
clients.use(f1, f2, f3)
// 使用数组添加
clients.use([f1, f2, f3])
⚠️

注意: 当前版本只有 async 的方法支持中间件,callback 暂不支持。

获取实例

这里获取实例的方式相对简单,直接调用get(name)即可,注意需要传入完整的service name,包括了包名。

const serviceAClient = clients.get('dev.path.to.serviceA')
const serviceBClient = clients.get('path.to.serviceB')
💡

注意: get()会缓存客户端,保证每次获取相同的客户端的时候,不会重复创建,减少消耗。getReal()提供获取没有缓存的客户端。

调用 rpc

调用 rpc 有两种方法,分别是asynccallback,正常情况下,我们更多是使用async语法。

async

这里直接使用async/await语法。

const result = await serviceAClient.rpcMethod(request, metadata, options)
  • rpcMethod(请求方法): 这是一个执行请求的方法。请求方法取决于定义的 gRPC 服务的.proto文件中的rpc,有4种形式,分别是点对点、流对点、点对流,流对流;
  • request(请求参数): 这是一个包含请求数据的对象。请求对象的结构取决于定义的 gRPC 服务的.proto文件中的消息类型;
  • metadata(元数据): 这是一个可选参数,用于传递与请求相关的元数据。元数据是以键值对的形式表示的信息,可以包含用于身份验证、授权、跟踪或其他目的的数据;
  • options(选项): 这是一个可选参数,用于设置特定的调用选项。它是一个包含一组键值对的对象,可用于配置调用的行为。一些可用的选项包括超时时间、重试策略等。如果不传该参数,默认会设置10秒超时,可以通过传入timeout的方式修改超时时间;

这里展示的是点对点的例子:

const meta = loader.makeMetadata({
    'x-business-id': ['grpcity', 'testing'],
    'x-timestamp-client': 'begin=' + new Date().toISOString()
})
const options = {
    timeout:  5000 // 表示在当前时间的 5 秒后超时。
}
 
const { status, peer, metadata, response } = await serviceAClient.rpcMethod({ name: 'myapp' }, meta, options)

client发起请求后,收到的结果包含了三个值,分别是statusmetadataresponse

  • status: 服务端处理执行后的状态;
  • peer: 客户端地址信息;
  • metadata: 服务端返回的 metadata 信息;
  • response: 服务端处理完成后响应的结果;

返回的结果示例:

{
  status: {
    code: 0,
    details: 'OK',
    metadata: Metadata { internalRepr: Map(0) {}, options: {} }
  },
  peer: '::9098',
  metadata: Metadata {
    internalRepr: Map(2) { 'content-type' => [Array], 'date' => [Array] },
    options: {}
  },
  response: { message: 'hello greeter by Greeter in server1', count: 1 }
}

callback

callback的调用需要多加一个原型链,如.call.

const a = serviceAClient.call.rpcMethod1({ name: 'myapp' }, (err, result) => {
    if (err) {
        throw err
    }
    return result
})
const b = serviceBClient.call.rpcMethod2({ name: 'youapp' }, (err, result) => {
    if (err) {
        throw err
    }
    return result
})

重新初始化

有一些业务场景是需要我们对 clients 进行重新初始化,例如:服务端的访问地址变更。这里提供的解决方法是先执行 clear(),在执行 init()

原理是清除上一次的客户端初始化时的所有缓存,再重新执行初始化,生成新的缓存信息。完整示例如下:

const clients = await loader.initClients({
    services: {
        'dev.path.to.serviceA': 'domain.local:9099',
        'path.to.serviceB': {
            host: '192.168.32.111',
            port: 10099
        }
    }
})
 
clients.clear()
 
clients.init({
    services: {
        'dev.path.to.serviceA': 'domain.local:9088',
        'path.to.serviceB': {
            host: '192.168.32.112',
            port: 10099
        }
    }
})
⚠️

注意: init()之前需要先执行clear(),否则会不生效。