Protobuf 解码
PAYLOAD
可选:粘贴
.proto 获得字段名功能说明
Protobuf 解码 把二进制 protobuf 消息拆成可读的 JSON。底层基于 protobufjs 解析
.proto,并配合手写的 wire format reader 做 schemaless 解码——所有处理都在浏览器本地完成,payload 和 schema 不会上传任何服务器。
两段式工作流
| 阶段 | 你提供 | 输出 |
|---|---|---|
| 无 schema 解码 | 仅 payload(hex / base64 / 文件) | field_<n>: value,每个 tag 给出 wire type + 多种类型解释 |
| 有 schema 解码 | payload + .proto + 选择 message 类型 | 带字段名的 JSON;.proto 没覆盖的 tag 仍以 _unknown_<n> 保留 |
切到 编码 模式可以反向操作:JSON +
.proto → hex/base64,方便构造测试用例。Wire format 速查
每个字段以 varint tag 开头:
(field_number << 3) | wire_type| wire type | 取值 | 用于 |
|---|---|---|
| 0 varint | int32/int64/uint32/uint64/sint32/sint64/bool/enum | 1–10 字节,最高位为 continuation bit |
| 1 i64 | fixed64/sfixed64/double | 固定 8 字节 |
| 2 len | string/bytes/embedded message/packed repeated | varint 长度 + 原始字节 |
| 5 i32 | fixed32/sfixed32/float | 固定 4 字节 |
| 3 / 4 sgroup / egroup | 已废弃 | proto2 早期遗留 |
常见坑
int32 vs sint32:编码不同,按错的解会得到完全不一样的数字(特别是负数)。一定要按 .proto 来
packed repeated:proto3 默认 packed,wire 上是 len 类型而不是多次重复同一 tag。无 schema 模式下会被识别为 bytes 或 message
gRPC 5 字节前缀:HTTP/2 抓包看到的 body 前 5 字节是 grpc framing,不是 protobuf 本身,要先剥掉
oneof:wire 上和普通字段没区别,只是 schema 上互斥;本工具有 schema 模式会按 oneof 选中的字段输出
未知字段:proto3 之前默认丢弃;本工具会主动保留并标 _unknown_<n>,避免漏掉对方加的新字段
使用场景
抓包看到二进制 body
gRPC / Protobuf-over-HTTP 抓到的 request/response body 是一坨字节,先无 schema 解出 tag 结构看个大概,再贴
gRPC / Protobuf-over-HTTP 抓到的 request/response body 是一坨字节,先无 schema 解出 tag 结构看个大概,再贴
.proto 升级到字段名。没拿到 .proto 也能调试
第三方接口或对方还没给 schema,照样能解出每个 tag 的 wire type、数值、字符串候选——很多排错只需要看到结构就够了。
第三方接口或对方还没给 schema,照样能解出每个 tag 的 wire type、数值、字符串候选——很多排错只需要看到结构就够了。
验证 SDK 编出的 payload
怀疑客户端 SDK 编错字段(比如把 sint32 写成 int32),把 wire 上抓到的字节贴进来对照
怀疑客户端 SDK 编错字段(比如把 sint32 写成 int32),把 wire 上抓到的字节贴进来对照
.proto 看有没有出入。反向构造测试用例
切到"编码"模式,输入
切到"编码"模式,输入
.proto + JSON 直接生成 hex/base64 二进制,喂给被测服务做边界测试,不用写脚手架。常见问题
为什么不需要 .proto 也能解?
Protobuf 的 wire format 本身在每个字段前都编码了
(field_number << 3) | wire_type,解码器据此能拆分出字段编号和类型大类(varint, i64, len 等),只是无法得知精确的类型名(如 int32 vs sint32)和字段名。解出来的 string / message / bytes 是怎么判断的?
对于 wire type 为 len 的字段,工具采用启发式算法:优先尝试作为嵌套消息递归解码,若成功则显示为 message;否则尝试作为 UTF-8 字符串解码,若可读则显示为 string;最后作为 bytes 处理。结果会附带 _wire 标记辅助判断。
int32 和 sint32 解出来不一样?
两者编码方式不同:int32 使用标准 varint 编码,sint32 使用 ZigZag 编码。无 schema 模式下会同时提供多种解释,有 schema 模式下会根据 .proto 定义自动选择正确的解码方式。
.proto 里有 import 怎么办?
浏览器环境不支持 .proto 文件的 import 语句,需要将所有依赖的 message 复制到同一份 .proto 中。google.protobuf.Timestamp 等常用类型已内置。
schema 里少声明的字段会丢吗?
不会。与 protoc --decode 不同,本工具不会静默丢弃 schema 未覆盖的字段,而是会主动保留并以 _unknown_<n> 为键显示在结果中。
为什么我的 long/int64 字段输出成字符串了?
这是为了在 JavaScript 中精确表示超过 2^53 的大整数。Number 类型在 JS 中无法精确表示 64 位整数,所以统一输出为字符串格式。
gRPC 抓包里前面的 5 个字节怎么处理?
HTTP/2 传输的 gRPC 数据前有 5 字节前缀(1 字节压缩标志 + 4 字节消息长度),这是 grpc framing,不是 protobuf 本身。解码前需先剥离这 5 字节。建议配合 Wireshark 的 gRPC 解码插件使用。
能解 protobuf-text-format 吗?
不能。本工具仅处理二进制 wire format,无法解码 Protobuf Text Format。
