【问题标题】:Invalid wire type and index out of range errors when consuming a protobuf message from .net with protobufjs on nodejs在 nodejs 上使用 protobufjs 使用来自 .net 的 protobuf 消息时出现无效的线路类型和索引超出范围错误
【发布时间】:2020-10-12 05:46:51
【问题描述】:

我正在尝试在节点 js 上使用来自 RMQ 的 protobuf 消息。 protobuf 消息是使用 C#.Net 上的 protobuf-net 创建的

例如,c# 对象如下所示:

    [ProtoContract]
    public class PositionOpenNotification : MessageBase
    {
    [ProtoMember(1)]
    public int PositionID { get; set; }

    [ProtoMember(2)]
    public int InstrumentID { get; set; }
    ..
    ..Down to tag 30

然后将其添加到 RMQ,我们在另一端使用具有相同对象的 .net 侦听器对其进行解码。

但是现在我们想从 nodejs 读取消息。 为此,我在 nodejs 端使用 amqplib 和 protobuf-js。

我试图使用带有如下装饰器的对象来解码消息:

import { Message, Type, Field } from "protobufjs/light"; 
 
 @Type.d("PositionOpenNotification")
 export class PositionOpenNotification extends Message<PositionOpenNotification> {
 
  @Field.d(1,"int32", "required")
  public PositionID: number;
}

然后像这样解码:

ch.consume(q.queue, function(msg, res) {
            try {
                if(msg.content) {
                    let decoded = PositionOpenNotification.decode( msg.content);
                    console.log(" Received %s", decoded,q.queue);
                }
              } catch (e) {
                 console.log("Error  %s ", e.message)
              }
        }

其中 ch 是 amqplib RMQ 通道。

但我总是遇到以下错误之一:

偏移 2 处的线类型 7 无效

偏移 2 处的线类型 4 无效

偏移 2 处的线类型 6 无效

索引超出范围:237 + 10 > 237

等

我做错了什么?

编辑:

看起来我没有考虑到 MessageBase(PositionOpenNotification 继承的抽象)也是一个 ProtoContract 并且数据以长度前缀序列化的事实。

所以最后这是有效的:

添加一个带有 PositionOpenNotification 对象的 MessageBase 对象:

@Type.d("MessageBase")
export class MessageBase extends Message<MessageBase> {

  @Field.d(108, PositionOpenNotification)
  public positionOpenNotification: PositionOpenNotification;
}

然后在反序列化时:

 if(msg.content) {
    var reader = Reader.create(msg.content);
    let decoded = MessageBase.decodeDelimited(reader);
 }

【问题讨论】:

    标签: node.js protocol-buffers protobuf-net protobuf.js node-amqplib


    【解决方案1】:

    电线类型 7 不存在,所以:至少错误是正确的。

    这种类型的错误通常表明负载在传输过程中已损坏。最常见的方法是将其视为文本,和/或(非常频繁地看到的东西):通过向后编码运行它以通过文本协议传输二进制数据。检查你没有这样做。基本上,您需要在两端获得完全相同的字节;在你拥有它之前,没有其他方法可以工作。特别是,如果您需要通过文本协议传输二进制文件:base-64 是您的朋友。

    附带说明:protobuf-net 具有为您的对象模型导出 .proto 架构的方法,以使 x-plat 更方便。寻找Serializer.GetProto&lt;T&gt;。

    如果您有不确定的负载,可以使用https://protogen.marcgravell.com/decode 来验证和检查二进制数据。

    【讨论】:

    • 因此,如果在使用 EasyNetQ 的同一个 RMQ 上已经有 .net 阅读器来读取此消息,唯一的区别是我使用 amqplib 来读取 nodejs 上的消息......所以我认为我得到的缓冲区相当于.net 上的字节数组。所以要么它不等效(但为什么?它不是文本协议),要么我的对象不正确。
    • 现在我看到 .net 阅读器实际上是在使用 Serializer.DeserializeWithLengthPrefix(stream, PrefixStyle.Base128) 反序列化,并且在 protobufjs 上等效的是 decodeDelimited 但没有 PrefixStyle 指示,它仍然失败...
    • 我也做了 GetProto,但仍然存在所描述的问题(由于非法值 '00000000-0000-0000-0000-000000000000' 错误,还需要删除 guid 的默认值)
    • @Mihir 有没有机会在这里看到一些有效载荷十六进制?这将使提供指导变得更加容易
    • 我刚刚找到了一种让它工作的方法......我将 PositionOpenNotification 作为一个子类型放在 MessageBase 对象上并且它有效,我将用答案编辑问题。谢谢你的帮助!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-05
    相关资源
    最近更新 更多