TypeScript / JavaScript gRPC google.protobuf.Struct 无法读取

TypeScript / JavaScript gRPC google.protobuf.Struct cannot be read

我有一个 TypeScript 服务器尝试使用 Struct 读取 JSON 对象,但它似乎只对包含“字段”键的对象有效,然后期望一个对象作为值。尽管如此,结构应该与任何 JSON 对象一起工作。

使用 BloomRPC 我正在尝试以下消息:

{
  "payload": {
    "fields": {
      "Hello": {
        "whatever": 0
      }
    }
  }
}

服务器读取:

{ fields: { Hello: {} } }

如果我发送:

{
  "payload": {
    "anotherfield": {
      "HelloWorld": {
        "whatever": 0
      }
    }
  }
} 

我在服务器上得到一个空对象。

简化的 protobuf 文件如下所示:

syntax = "proto3";

import "google/protobuf/struct.proto";

// The service definition.
service TestTicketService {
  rpc UpdateTicket (UpdateTicketRequest) returns (UpdateTicketResponse);
}

// The request message containing the required ticket information.
message UpdateTicketRequest {
    string ticketId = 1;
    google.protobuf.Struct payload = 2;
}

// The response message containing any potential error message
message UpdateTicketResponse {
  string error = 1;
}

知道为什么 google/protobuf/struct.proto 没有按预期工作吗?

真正让我困惑的是,我试图传递正常的 JSON 对象并期望读取它们。重点是,从客户端来看,JSON 对象需要以非常特定的方式进行编码。

例如:

"payload": {
    "fields": {
      "name": {
        "stringValue": "joe"
      },
      "age": {
        "numberValue": 28
      }
    }
  }

您可以通过查看此处的 Struct proto 文件来确定消息的格式:https://googleapis.dev/nodejs/asset/latest/v1_doc_google_protobuf_doc_struct.js.html

结构的理念是您可以存储任意数据 - 但只能存储简单类型:null、数字、字符串、布尔值、数组和对象。

这与 JSON 完美对应,这并非偶然。 google.protobuf.Struct 消息有一个特殊的 JSON 表示:

The JSON representation for Struct is JSON object.

所以你可以将任何JSON字符串解析成一个protobuf结构,当再次序列化为JSON时,你也会再次得到相同的JSON字符串。

重要的是要注意已解析结构的内存中表示不等于 JSON 对象。 Protobuf 没有动态字段,必须以更复杂的方式表示 JSON 数据。这就是为什么 struct.proto 定义了一些其他类型。

当您想在 JavaScript 中创建结构时,最简单的方法可能是只创建您想要的 JSON 对象:

var jsonObject = {foo: "bar"};
var jsonString = JSON.stringify(jsonObject);

现在您可以从这个 jsonObject 或 jsonString 解析 Struct,并将结果 Struct 设置为另一个 protobuf 消息中的字段值。

由于您已经在使用 TypeScript,因此可能值得检查 protobuf 的替代 TypeScript 实现之一。 我是 protobuf-ts 的作者。创建结构非常简单:

let struct = Struct.fromJson({foo: "bar"});

首先,安装 @types/google-protobuf 和:

  let rqm = new UpdateTicketRequest();
  rqm.setTicketId("1");
  rqm.setPayload(Struct.fromJavaScript({
    Hello:{
      whatever: 0,
    }
  });
  //and call the api....
  UpdateTicket(rqm);