@grpc/grpc-js能否动态解析google.protobuf.Any类型?
动态解析gRPC中google.protobuf.Any类型的错误详情
我正在用@grpc/grpc-js开发gRPC客户端,需要处理服务器流式Init方法返回的错误:返回的InitResponse里包含google.rpc.Status对象,其details数组的元素是google.protobuf.Any类型,我需要解析这些应用特定的错误,但无法预先知晓错误的具体类型。
相关Proto定义
Init方法定义:
// Initializes an existing Arduino Core instance by loading platforms and // libraries rpc Init(InitRequest) returns (stream InitResponse) {}
InitResponse定义:
message InitResponse { message Progress { // Progress of the downloads of platforms and libraries index files. DownloadProgress download_progress = 1; // Describes the current stage of the initialization. TaskProgress task_progress = 2; } oneof message { Progress init_progress = 1; google.rpc.Status error = 2; // Selected profile information Profile profile = 3; } }
错误详情示例
details数组中的Any类型示例:
{ "typeUrl": "type.googleapis.com/cc.arduino.cli.commands.v1.PlatformLoadingError", "value": "" }
{ "typeUrl": "type.googleapis.com/cc.arduino.cli.commands.v1.FailedInstanceInitError", "value": "CAIStAFMb2FkaW5nIGluZGV4IGZpbGU6IGxvYWRpbmcganNvbiBpbmRleCBmaWxlIC9Vc2Vycy9hLmtpdHRhL0xpYnJhcnkvQXJkdWlubzE1L3BhY2thZ2VfaW5kZXguanNvbjogb3BlbiAvVXNlcnMvYS5raXR0YS9MaWJyYXJ5L0FyZHVpbm8xNS9wYWNrYWdlX2luZGV4Lmpzb246IG5vIHN1Y2ggZmlsZSBvciBkaXJlY3Rvcnk=" }
已知类型的常规处理方式
如果预先知道错误类型,可以用Any#unpack方法解析,示例代码如下:
const error: Status | undefined = resp.getError(); if (error) { const details: Any[] = error.getDetailsList(); if (details.length) { const any = details[0]; const typeName = any.getTypeName(); switch (typeName) { case 'cc.arduino.cli.commands.v1.FailedInstanceInitError': { const initError = any.unpack( FailedInstanceInitError.deserializeBinary, typeName ); console.log('Handle the init error', initError); break; } case 'cc.arduino.cli.commands.v1.PlatformLoadingError': { const loadError = any.unpack( PlatformLoadingError.deserializeBinary, typeName ); console.log('Handle the load error', loadError); break; } default: { console.log('Unexpected error'); } } } }
核心问题
能否通过typeName动态获取对应类型的反序列化方法?根据protocolbuffers/protobuf-javascript的讨论,这似乎没有官方支持,想了解业界的最佳实践是什么?
临时可行方案
我找到了一个临时解决方案:proto生成的JS模块中,deserializeBinary方法会挂载到全局对象的proto属性下,借助get-value包可以编写一个通用函数来获取该方法:
import { Message } from 'google-protobuf'; import get = require('get-value'); export function globalDeserializeBinary<T extends Message = Message>( typeName: string ): ((data: Uint8Array) => T) | undefined { return get(global, ['proto', typeName, 'deserializeBinary'].join('.')); }
修改后的解析代码:
const error: Status | undefined = resp.getError(); if (error) { const details: Any[] = error.getDetailsList(); if (details.length) { const any = details[0]; const typeName = any.getTypeName(); const deserialize = globalDeserializeBinary(typeName); if (deserialize) { const error = any.unpack(deserialize, typeName); if (error) { console.log('BLABLA', JSON.stringify(error.toObject(false))); } } } }
运行后可以得到预期的错误对象:
BLABLA {"reason":2,"message":"Loading index file: loading json index file /Users/a.kitta/Library/Arduino15/package_index.json: open /Users/a.kitta/Library/Arduino15/package_index.json: no such file or directory"} BLABLA {"reason":2,"message":"Loading index file: loading json index file /Users/a.kitta/Library/Arduino15/package_teensy_index.json: open /Users/a.kitta/Library/Arduino15/package_teensy_index.json: no such file or directory"} BLABLA {} BLABLA {}
内容的提问来源于stack exchange,提问作者kittaakos
相关产品推荐
相关产品推荐

