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 有两种方法,分别是async和callback,正常情况下,我们更多是使用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发起请求后,收到的结果包含了三个值,分别是status、metadata和response。
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(),否则会不生效。