联调定位字段错位
客户端上报的日志里,用户 ID 和订单金额混在一起,后端解析出的 JSON 字段名对不上。联调群里两边各执一词,谁都不承认序列化顺序写错。把双方 proto 定义同时粘贴进来,再丢入二进制报文,工具直接按定义反序列化出字段名和值,一眼看出服务端多塞了一个 int32 导致后续字段偏移,五分钟定位问题。
开发者工具 · JSON / 数据格式
proto 定义 + 二进制→JSON
调试 gRPC 接口时,最怕的是拿到一串二进制 protobuf 数据却不知道里面是什么。把 .proto 定义文件和二进制数据贴进去,它实时解析成可读的 JSON 结构,字段名、嵌套层级、枚举值一一对应。解析过程在服务器端完成,原始数据不会被记录或存储——适合对接第三方 API 时快速验证编码是否正确。
客户端上报的日志里,用户 ID 和订单金额混在一起,后端解析出的 JSON 字段名对不上。联调群里两边各执一词,谁都不承认序列化顺序写错。把双方 proto 定义同时粘贴进来,再丢入二进制报文,工具直接按定义反序列化出字段名和值,一眼看出服务端多塞了一个 int32 导致后续字段偏移,五分钟定位问题。
后端升级了 proto 文件,新增了三个 optional 字段,但线上还有 30% 的旧版客户端没更新。运维需要确认旧版发来的二进制在新 proto 下能否正常解析,不崩也不丢核心字段。把新旧两版 proto 定义分别贴入,用同一段旧版二进制报文跑两遍,对比输出 JSON 的结构差异,确认旧版缺失的字段被正确填了默认值,核心字段完整,才敢灰度上线。
从 Wireshark 里拷出一段 TCP 载荷,十六进制数据 300 多字节,全是 08 12 1A 这种字节码。开发想确认里面是否包含用户的手机号字段,但手算 varint 和字段 tag 太慢,容易数错偏移。把 proto 定义和十六进制串一起丢进去,工具自动按 field number 和 wire type 拆出每个字段的值,直接看到第 5 个字段是 string 类型,内容正是手机号,省去半小时手工推算。
写单元测试时,需要构造一个包含嵌套 message 的 protobuf 二进制 payload,但手拼字节流容易错。先用 proto 定义声明好结构,再在工具里填入期望的字段值(如用户 ID=1024,订单金额=99.8),工具自动生成对应的二进制字节串。直接把这个字节串塞进测试用例的 mock 输入,省去写序列化代码的环节,且保证构造的二进制合法。
接了一个第三方支付 SDK,文档只给了 proto 文件,但线上抓包发现实际报文里多了一个 unknown field。怀疑是 SDK 内部加了调试字段,但对方不承认。把二进制报文和官方 proto 定义输入工具,解析结果里标出 unknown field 的 field number 和 raw bytes,截图发给对方技术,对方才承认是内部版本号字段忘记在文档里公开,省去反复扯皮。
| 输入 | 输出 | 说明 |
|---|---|---|
| proto: message Person { optional string name = 1; optional int32 age = 2; optional string email = 3; } bin: 0x0a046a6f686e10190a0a6a6f686e40656d61696c | {"name":"john","age":25,"email":"john@email"} | 常规:标准 proto3 消息,包含 string、int32 字段,验证基本字段解析与顺序 |
| proto: message Test { repeated int32 ids = 1; } bin: 0x0a03010203 | {"ids":[1,2,3]} | 常规:repeated 字段(packed 编码),验证数组类型正确解析 |
| proto: message Empty {} bin: 0x | {} | 边界:空消息(无字段定义),验证空输入输出空对象 |
| proto: message Large { optional string big = 1; } bin: 0x0a00000a0000 | {"big":""} | 边界:字段值为空字符串(长度 0),验证空值不丢失字段 |
| proto: message Nested { message Inner { optional int32 x = 1; } optional Inner inner = 1; } bin: 0x0a020801 | {"inner":{"x":1}} | 边界:嵌套消息,验证递归解析与层级结构 |
| proto: message EnumTest { enum Color { RED = 0; GREEN = 1; } optional Color c = 1; } bin: 0x0801 | {"c":"GREEN"} | 易错:枚举值解析为字符串名称而非数字,需注意枚举值 0 的默认行为 |
| proto: message Mixed { optional float f = 1; optional double d = 2; optional bool b = 3; } bin: 0x0d0000204209110000000000000040 | {"f":40.0,"d":2.5,"b":true} | 易错:浮点数与布尔值的二进制表示(小端序、IEEE 754),验证浮点精度与布尔值映射 |
1.二进制数据未做 Base64 编码直接粘贴
直接粘贴原始二进制字节(如 0x0A 0x1B 等十六进制文本)将二进制数据先转换为 Base64 字符串(如使用 base64 命令或在线工具)再粘贴本工具输入框接受文本,二进制数据包含不可见字符,直接粘贴会破坏数据完整性。Base64 是 protobuf 官方推荐的二进制文本传输编码。
2.proto 定义中字段类型与二进制数据不匹配
proto 定义字段为 int32,但二进制数据对应的是 sint32 编码的负数确保 proto 字段类型与编码端一致,负数用 sint32 或 sfixed32,uint32 无法表示负数Protobuf 的编码方式因类型而异:int32 对负数用 10 字节 zigzag 编码,而 sint32 用变长 zigzag。类型不匹配会导致解析出错误值或解析失败。
3.proto 定义中字段编号与二进制数据不对应
二进制数据中字段编号为 5,但 proto 定义中编号 5 对应的字段类型是 string核对二进制数据生成端 proto 文件,确保字段编号和类型完全一致Protobuf 二进制流通过 field_number + wire_type 识别字段。编号相同但类型不同时,解析器会按 proto 定义的类型读取,导致数据错位或乱码。
4.忘记处理 repeated 字段的 packed 编码
proto 定义 repeated int32 ids = 1,二进制数据是 packed 编码,但 proto 未加 [packed=true]在 proto 定义中明确标注 packed 属性:repeated int32 ids = 1 [packed=true];Protobuf 3 默认对基本类型 repeated 字段启用 packed 编码。如果 proto 2 未声明 packed,解析器会按非 packed 格式读取,导致字段解析为多个独立值而非数组。
5.未区分 oneof 字段导致多值冲突
proto 定义 oneof 包含 string name 和 int32 age,二进制数据同时包含两者确保 oneof 字段在二进制数据中只出现其中一个,或检查生成端逻辑Protobuf oneof 语义是互斥的,同时设置多个字段会导致最后一个覆盖前面的。解析时只会保留最后一个出现的字段,其余被静默丢弃。
6.map 字段的 key 类型使用浮点数
proto 定义 map<double, string> scores = 1;map 的 key 必须使用整数或字符串类型:map<string, string> scores = 1;Protobuf 规范明确禁止浮点数、bytes、enum 作为 map 的 key 类型。浮点数存在精度和相等比较问题,编译 proto 文件时会直接报错。
7.忽略 enum 值的默认行为
二进制数据中 enum 字段值为 0,但 proto 中 0 对应的枚举名是 UNKNOWN确认业务逻辑中 0 值 enum 的含义,必要时在 proto 中将 0 定义为有效值Protobuf 3 中,未设置的 enum 字段默认值为 0。如果 0 对应的枚举名是 UNKNOWN,解析结果会显示 UNKNOWN,可能被误认为数据异常。
8.嵌套 message 的二进制数据未正确拼接
将外层 message 和内层 message 的二进制数据直接拼接后传入按 protobuf 序列化规则,内层 message 作为外层的一个字段整体序列化,不可拆分嵌套 message 在二进制中是一个 length-delimited 字段,内层数据作为 bytes 整体嵌入。手动拼接会破坏字段边界,导致解析时字节错位。
JSON = decode(proto, binary) 其中 decode 按 proto 定义的字段类型、顺序、嵌套规则将二进制数据反序列化为 JSON 对象
protoProtocol Buffers 的 .proto 定义文本binaryBase64 编码或原始字节的 Protobuf 序列化数据JSON解码后输出的结构化 JSON 对象proto 定义:message Person { required int32 id = 1; required string name = 2; };binary 为 Base64 编码的字节流 CgVhZG1pbhAB(对应 id=1, name="admin")。解码过程:按 proto 字段顺序读取 tag 1(int32 类型,值 1)和 tag 2(length-delimited 字符串,长度 5,内容 "admin"),组装为 JSON:{"id":1,"name":"admin"}。
不能直接使用。本工具需要同时提供 .proto 定义文件(描述消息结构)和对应的序列化二进制数据(如 gRPC 响应体、Kafka 消息体等),才能将二进制解析为 JSON。如果仅有 .proto 文件,可先用其他工具生成模拟二进制数据,或确认数据源是否已提供序列化后的字节流。
本工具目前仅支持单个 .proto 文件解析,不支持自动解析 import 语句。如果 .proto 文件依赖其他类型(如 google/protobuf/timestamp.proto),需要将这些依赖的 .proto 文件内容手动合并到主文件内,或精简掉无关 import 后上传。建议在提交前用 protoc 命令验证合并后的文件是否合法。
这是由 .proto 定义中的字段名直接决定的。Protobuf 默认使用下划线命名(如 user_name),工具不做额外转换。如果期望输出驼峰格式(如 userName),需要在 .proto 文件中显式声明 json_name 选项,例如:string user_name = 1 [json_name = "userName"];否则字段名与 .proto 保持一致。
本工具为后端 Go 实现,处理 10MB 以内的二进制数据通常在 1-3 秒内完成,具体取决于 .proto 定义的复杂度(如嵌套消息数量、重复字段层级)。超过 50MB 的二进制数据建议分块处理或使用本地 protoc 命令,因为 HTTP 传输本身会占用较多时间。工具对单次请求的二进制大小限制为 100MB。
Protobuf 标准中时间戳字段通常定义为 google.protobuf.Timestamp 类型,其序列化后是秒和纳秒两个整数。本工具目前直接输出这两个整数字段,不自动格式化为可读日期。如需可读时间,可在 .proto 中改用 string 类型并自行定义时间格式,或解析后使用外部脚本转换。
常见原因有两种:一是二进制数据可能经过了 base64 编码,但工具要求的是原始字节流,需要先解码为二进制再上传;二是 .proto 定义中的字段编号与二进制数据实际使用的编号不一致(例如 proto 文件已更新但二进制是旧版本生成的)。建议先用 protoc --decode_raw 命令验证二进制是否能被正确解码。
不会。工具采用后端 Go 实现,数据仅在内存中完成解析后立即返回结果,不会写入磁盘或数据库。解析完成后,服务器端的内存会被回收,不会留存任何用户数据。但出于网络传输安全考虑,建议不要在二进制数据中包含敏感信息(如密码、密钥),如需处理敏感数据可考虑本地部署的 protoc 工具。
主要优势是免安装、免配置。使用 protoc 需要本地安装 Protobuf 编译器、配置包含路径、处理依赖,对不熟悉命令行的开发者有一定门槛。本工具直接在浏览器中操作,上传文件即可得到结果,适合快速调试或临时验证。但 protoc 支持更复杂的选项(如自定义输出格式、多文件依赖解析),适合集成到构建流程中。
隐私保证所有计算与处理均在你的浏览器本地完成,输入数据不会上传服务器,也不会保存或共享。