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()
,否则会不生效。