Protobuf 解码
粘贴十六进制或 Base64,按 wire format 拆出字段号、数值和嵌套结构,不需要 .proto 文件。
十六进制可以带空格、逗号或 0x 前缀;Base64 的换行也会被忽略。示例是 { 1: 150, 2: "hello", 3: { 1: true } }。
已解析14 字节 · 十六进制输入 · 3 个顶层字段
怎么读这个结果
每行开头的数字是字段号,括号里是 wire type。varint 是变长整数,length-delimited 带着自己的字节数,fixed32 和 fixed64 是定长数值,按 float 或 double 解释。缩进两格的是上一条字段里的嵌套消息。
字段号从 1 开始,1 到 15 只占一个字节的标签,所以高频字段一般排在前面;19000 到 19999 是 protobuf 保留区,不能自定义。看到 0 号字段说明数据不是 protobuf,或者偏移已经错了。
wire type 2 的判定顺序是启发式的:先试 UTF-8 文本,再试嵌套消息,然后试 packed varint,都不成立就按十六进制显示。所以「看起来像字符串的嵌套消息」会被读成字符串,反过来一段恰好符合消息结构的文本也可能被展开——两边在结果里都能看到原始字节,可以对照判断。
要对比另一种二进制序列化格式,用MessagePack 编解码或CBOR 编解码;要看 JSON 结构差异,用JSON 结构化对比。
常见问题
没有 .proto 为什么也能解?
Protobuf 的每个字段都带着 (字段号 << 3 | 类型) 的 varint 标签,长度分隔的字段还写明了自己的字节数。所以字段号、边界和嵌套关系是自描述的,能还原出结构;拿不到的只有字段名、枚举值和 sint 与 int 的区别。
为什么显示的是字段号而不是字段名?
字段名只存在于 .proto 文件里,不写进二进制。想知道 1 号字段叫什么,只能对照服务端的 proto 定义。字段号本身也是兼容性契约的一部分,改号会直接读错,所以排查时看到号也能对上代码。
varint 的值为什么可能不是真实数字?
wire type 0 只说明它是个变长整数,具体是 int32、int64、uint64、bool 还是 enum,要靠 schema 判断。负数用补码编码时会变成很大的正数,sint32/sint64 则用 zigzag,同一个字节串在两套解释下结果不同。
怎么区分字符串和嵌套消息?
wire type 2 只说明是长度分隔的字节串,到底是 string、bytes、嵌套消息还是 packed repeated,二进制里没有标记。工具按「可打印 UTF-8 → 嵌套消息 → packed varint → 十六进制」的顺序猜,猜错时结果里会标出来。
为什么有时候解析到一半就停了?
多半是数据被截断,或者粘进来的不是完整的消息。解析器遇到长度前缀超出剩余字节、varint 没有终止位时会停下来,并在下面列出停在哪一个偏移。把完整的响应体重发一次通常就好了。
结果可以直接拿去生成代码吗?
不能。这里只有字段号和推断出的类型,没有字段名、默认值和 oneof 关系。要生成代码还是得写 .proto,或者用 protoc --decode_raw 对照着看,两者结果可以互相印证。