我一直在努力在系统之间来回传递带有消息值的 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.stringify
和 JSON.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/