protocol-buffers - GRPC:在浏览器和服务器之间传递带有 proto.Message 字段的 JSON

标签 protocol-buffers grpc grpc-web

我一直在努力在系统之间来回传递带有消息值的 JSON。又走了一点,但我还没到。结构似乎是一种方法,但即使我发送的结构看起来非常好,但一旦被服务器接收到,它就是空的。

Result 从 Web 浏览器 (grpc-web) 传递到 Python 后端。 Python 后端应将 Result 序列化为 JSON(以存储它)并再次返回。

// proto
message Result {
    google.protobuf.Struct variables = 1;
}

// obj - Where variables would contain a (1 level deep) JSON with different types of values, e.g.:
{
    "key1": 1,
    "key2": true,
    "key3": proto_msg_a //instance of proto.MessageA
}

// code
struct = new proto.google.protobuf.Struct(obj);
req = new Request;
req.variables = struct;

在发送之前检查 req.variables 表明它确实是一个 Struct ,其中包含所有正确的字段。但是,一旦另一端(服务器)收到它,req.variables 就是一个空的 Struct。出于测试目的,我尝试了一个简单的 obj,即 {'key': 'value'},但结果是相同的。

然后我尝试了proto.google.protobuf.Struct.fromJavaScript:

// code
struct = proto.google.protobuf.Struct.fromJavaScript(vars);
req = new Request;
req.variables = struct;

这适用于简单的 obj (例如 {"key": "val"}),但适用于带有原型(prototype)的 obj消息字段(如上面)导致:

struct_pb.js:875 Uncaught Error: Unexpected struct type.
    at Function.proto.google.protobuf.Value.fromJavaScript (struct_pb.js:875)
    at Function.proto.google.protobuf.Struct.fromJavaScript (struct_pb.js:941)
    at Function.proto.google.protobuf.Value.fromJavaScript (struct_pb.js:871)
    at Function.proto.google.protobuf.Struct.fromJavaScript (struct_pb.js:941)
    at Function.proto.google.protobuf.Value.fromJavaScript (struct_pb.js:871)
    at Function.proto.google.protobuf.Struct.fromJavaScript (struct_pb.js:941)
    at Function.proto.google.protobuf.Value.fromJavaScript (struct_pb.js:871)
    at Function.proto.google.protobuf.Struct.fromJavaScript (struct_pb.js:941)

或者我可以不用在 javascript 中经历 protobuf/json 的所有麻烦,而只使用 map 吗?

// proto
message Request {
    map<string, ?type?> variables = 1;
}

但是如果值可以是任何东西(proto.MessageX、字符串、 bool 值等),那么 ?type? 会是什么?

我真的很想在变量中使用原始消息。选择 protobuf/grpc 的原因正是如此,能够在我们整个平台上使用相同的类型,但这似乎阻碍了这一目标。我错过了什么?你会做什么?

最佳答案

我没有准确回答您的问题,但我遇到了可能与此相关的 Struct.fromJavaScript 问题。

TL;DR

在传递给 Struct.fromJavaScript 的任何内容中都不能有 未定义(或任何无效的 JSON)。如果您传递对象,这包括任何深度嵌套的字段。

我解决这个问题的方法是先将我想要转换为 Struct 的对象 JSON.stringifyJSON.parse 传递给 Struct.fromJavaScript 删除所有包含无效 JSON 的字段:

const obj = { ... }

const stringifiedJSON = JSON.stringify(obj)
const parsedJSON = JSON.parse(stringifiedJSON)

const newStruct = Struct.fromJavaScript(parsedJSON)

我一直在寻找导致此错误的原因,看起来在 google-protobuf 的结构实现中,有一个 switch 语句,如下所示:

proto.google.protobuf.Value.fromJavaScript = function(value) {
  var ret = new proto.google.protobuf.Value();
  switch (goog.typeOf(value)) {
    case 'string':
      ret.setStringValue(/** @type {string} */ (value));
      break;
    case 'number':
      ret.setNumberValue(/** @type {number} */ (value));
      break;
    case 'boolean':
      ret.setBoolValue(/** @type {boolean} */ (value));
      break;
    case 'null':
      ret.setNullValue(proto.google.protobuf.NullValue.NULL_VALUE);
      break;
    case 'array':
      ret.setListValue(proto.google.protobuf.ListValue.fromJavaScript(
          /** @type{!Array} */ (value)));
      break;
    case 'object':
      ret.setStructValue(proto.google.protobuf.Struct.fromJavaScript(
          /** @type{!Object} */ (value)));
      break;
    default:
      throw new Error('Unexpected struct type.');
  }
  return ret;
};

看起来它只是遍历对象字段并检查字段的类型,如果类型不是前面的情况之一,它将抛出意外的结构类型错误。这意味着如果该字段未定义,则会抛出错误。

此外,Struct.fromJavaScript 上的类型定义是这样的:

(method) Struct.fromJavaScript(value: {
    [key: string]: JavaScriptValue;
}): Struct

其中 JavaScriptValue

export type JavaScriptValue = null | number | string | boolean | Array<any> | {};

如果您直接将 undefined 对象传递到 fromJavaScript 中,而不是通过类型化变量...

Struct.fromJavaScript({
  field: undefined, // this will cause a compile-time error
})

// ----------

type WeirdObj = {
  field?: string
}

const obj: WeirdObj = {
  field: undefined,
}

Struct.fromJavaScript(obj) // this will throw a run-time error

// ----------

type WeirdUndefinedObj = {
  field: string | undefined
}

const undefinedObj: WeirdUndefinedObj = {
  field: undefined,
}

Struct.fromJavaScript(undefinedObj) // this will cause a compile-time error

这让我困惑了一段时间,因为 fromJavaScript (对我来说)似乎我可以将 JavaScript 传递给它,并且我会得到一个结构作为返回。也许该方法应该改为 fromJSON,并更新类型以防止 undefined 首先传递到该方法中。

关于protocol-buffers - GRPC:在浏览器和服务器之间传递带有 proto.Message 字段的 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62693938/

相关文章:

node.js - 解码后的时间戳与原始日期时间值不同

c# - 如何在 .NET Framework 中创建 gRPC 客户端?

go - 使用 golang 客户端的 GRPC Web 请求?

google-cloud-platform - 谷歌端点 + grpc-web

go - gRPC 私有(private) channel

python - 有没有办法使用 python 3.x 访问 Protocol Buffer ?

c++ - 用于构建 C++ Google Protocol Buffers 项目的 Makefile

c++ - 使用 protobuf 对象作为 std::map 中的键

node.js - gRPC Node : How to set a field that is of another Message type (with multiple types itself)