1

我一直在努力在系统之间来回传递带有 Message 值的 JSON。走得更远了,但我还是不在。A Struct 似乎是一种方式,但即使我发送的结构看起来非常好,一旦被服务器接收到它就是空的。

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

// 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表明它确实是 a Struct,其中包含所有正确的字段。但是一旦另一端(服务器)收到它req.variables就是一个空的Struct. 出于测试目的,我尝试了objthat is simple {'key': 'value'},但结果是一样的。

所以我尝试了proto.google.protobuf.Struct.fromJavaScript

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

这适用于简单的obj(例如{"key": "val"}),但对于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;
}

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

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

4

1 回答 1

0

我没有准确回答你的问题,但我遇到的问题Struct.fromJavaScript可能有点相关。

TL;博士

undefined无论您传递给Struct.fromJavaScript. 如果您传递一个对象,这包括任何深度嵌套的字段。

我为我的解决方案解决这个问题的方法是,JSON.stringifyJSON.parse想在传递它之前将它变成一个 StructStruct.fromJavaScript以删除所有具有无效 JSON 的字段:

const obj = { ... }

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

const newStruct = Struct.fromJavaScript(parsedJSON)

我一直在寻找导致此错误的原因,看起来在 struct 的实现中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;
};

看起来它只是遍历对象字段并检查字段的类型,然后Unexpected struct type如果类型不是以前的情况之一,它将抛出错误。这意味着如果该字段是undefined,则会抛出错误。

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

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

JavaScriptValue在哪里

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

如果你直接传递一个对象,undefinedfromJavaScript不是通过一个类型化的变量......

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首先传递到该方法中。

于 2021-06-15T17:24:07.057 回答