You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

protobufjs中protobuf.encode()功能不符合预期问题求助

protobufjs v7.2.3 编码异常:编码后字段丢失,解码仅保留部分字段

问题详情

使用protobufjs v7.2.3版本时,调用ReceiverSetting.encode()后生成的buffer仅为<Buffer 12 00>,解码后大部分字段丢失,仅保留domainOverride和listen字段。protobuf.verify()校验无错误,属性已按代码设置,文件及导入流程正常,其他场景同类使用无异常,该问题已耗时4天未解决。

代码片段

let settings = {
    port_list: {
        range: [{
            From: 1,
            To: 100
        }]
    },
    listen: {},
    allocation_strategy: {},
    stream_settings: {},
    receive_original_destination: {},
    sniffing_settings: {
        enabled: false
    }
}
let error = ReceiverSetting.verify(settings)
let receiverSetting = ReceiverSetting.create(settings)
console.log('error: ', error)
const buffer = ReceiverSetting.encode(receiverSetting).finish();
console.log('receiverSetting:', receiverSetting);
console.log('buffer:', buffer);
const decodedMessage = ReceiverSetting.decode(buffer);
console.log('decodedMessage:', decodedMessage);

日志输出

error:  null
receiverSetting: ReceiverConfig {
  domainOverride: [],
  port_list: { range: [ [Object] ] },
  listen: {},
  allocation_strategy: {},
  stream_settings: {},
  receive_original_destination: {},
  sniffing_settings: {}
}
buffer: <Buffer 12 00>
decodedMessage: ReceiverConfig { domainOverride: [], listen: IPOrDomain {} }

对应Proto文件定义

syntax = "proto3";

package xray.app.proxyman;

import "common/net/address.proto";
import "common/net/port.proto";
import "transport/internet/config.proto";
import "common/serial/typed_message.proto";

// ... 省略其他定义 ...

message ReceiverConfig {
  xray.common.net.PortList port_list = 1;
  xray.common.net.IPOrDomain listen = 2;
  AllocationStrategy allocation_strategy = 3;
  xray.transport.internet.StreamConfig stream_settings = 4;
  bool receive_original_destination = 5;
  reserved 6;
  repeated KnownProtocols domain_override = 7 [ deprecated = true ];
  SniffingConfig sniffing_settings = 8;
}

message SniffingConfig {
  // Whether or not to enable content sniffing on an inbound connection.
  bool enabled = 1;

  // Override target destination if sniff'ed protocol is in the given list.
  // Supported values are "http", "tls", "fakedns".
  repeated string destination_override = 2;
  repeated string domains_excluded = 3;

  // Whether should only try to sniff metadata without waiting for client input.
  // Can be used to support SMTP like protocol where server send the first
  // message.
  bool metadata_only = 4;

  bool route_only = 5;
}

// ... 省略其他定义 ...

问题分析与解决办法

1. 字段名大小写不匹配

代码中port_list.range使用大写开头的From和To,但Proto3规范中字段名默认采用蛇形命名(如from、to),protobufjs会严格匹配Proto文件中的字段名。若xray.common.net.PortRange定义为:

message PortRange {
  int32 from = 1;
  int32 to = 2;
}

则代码需改为小写字段名,否则verify不会报错,但create时会忽略不匹配字段,导致port_list无有效内容被编码:

port_list: {
    range: [{
        from: 1,
        to: 100
    }]
}

2. 布尔类型字段赋值错误

receive_original_destination是Proto定义的bool类型,代码中赋值为空对象{}类型不匹配,编码时会直接忽略该字段,需改为布尔值:

receive_original_destination: false // 或true,根据业务需求设置

3. 嵌套消息类型初始化问题

allocation_strategy、stream_settings是自定义消息类型,直接传空对象{}无法被protobufjs识别为合法实例,编码时会跳过。需使用对应类型的create方法初始化:

allocation_strategy: AllocationStrategy.create({}),
stream_settings: StreamConfig.create({})

(前提是这些类型已正确导入并加载)

4. 默认值字段未编码

Proto3中布尔类型默认值为false,sniffing_settings.enabled = false属于默认值,protobufjs默认不会编码默认值字段。若需强制编码,需在encode时添加alwaysEncodeDefaults选项:

const buffer = ReceiverSetting.encode(receiverSetting, { alwaysEncodeDefaults: true }).finish();

5. 嵌套类型未正确加载

确保PortList、IPOrDomain、AllocationStrategy、StreamConfig、SniffingConfig等所有依赖的Proto类型都已通过protobufjs正确加载(比如使用load或loadSync方法加载所有相关Proto文件),否则create方法无法解析嵌套对象,导致字段被忽略。

内容的提问来源于stack exchange,提问作者Ezioadf2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 18:07:13