Protobuf 转 JSON

Protobuf 二进制在线解析为 JSON,有没有 .proto 都能解:支持十六进制、Base64、gRPC 帧,int64 和 Timestamp 按 ProtoJSON 输出不丢精度,也能把 JSON 编码回二进制。

  • 在浏览器中处理
  • 数据不离开你的设备
  • 免费 · 无需注册
“二进制 → JSON”解码 Protobuf 字节。“JSON → 二进制”把 ProtoJSON 编码回字节,需要 .proto Schema 和消息类型。“示例 JSON”把所选类型的每个字段各列一次,值为占位值。三种模式都随输入更新输出。切到“JSON → 二进制”时如果 JSON 框为空,会填入由字节解码得到的 JSON。
字节按哪个消息解码,或 JSON 按哪个消息编码。列表里是你的 .proto 文件中的类型,默认选中第一个没有被其他类型用作字段的类型,一般就是顶层消息。“不用 Schema(原始解码)”只在“二进制 → JSON”中出现,按线路格式读取,不带字段名。
“自动”会识别十六进制、Base64、转义字符串或字节列表,并在状态栏写明按哪种格式读取。同一段文本既是合法十六进制又是合法 Base64 时按十六进制读取并给出说明;读错了就在这里选 Base64。 “自动”在输入以帧标志(00、01、80 或 81)开头、且各个 5 字节帧头正好覆盖全部输入时去掉 gRPC 帧。多条消息输出为 JSON 数组,gRPC-Web 的 trailers 写进说明,带压缩标志的帧先用 gzip 解压;其他压缩方式不支持。“有”在帧不完整时报错。“无”把所有字节都当作消息内容。 “lowerCamelCase”输出每个字段的 ProtoJSON 名:有 json_name 选项时用它,否则把字段名转成 lowerCamelCase。“与 .proto 相同”按 Schema 里的写法输出。“JSON → 二进制”两种写法都接受,与这里的选择无关。 ProtoJSON 不输出取默认值(0、空字符串、false、枚举第一个值)的无存在性字段(proto3 普通字段),也不输出空的 repeated 和 map 字段。勾选后输出它们。有存在性的字段(optional、oneof、消息字段)只有在字节里设置了才输出。 不用 Schema 解码时字节怎样显示。“JSON”把长度前缀的值显示为文本(可读时)、嵌套对象(能按消息解析时)或 base64。“JSON,附其他解读”还列出每个数字按同一线路类型的其他类型读出的值,例如 sint64、sfixed64、float、double。“protoc --decode_raw”输出 protoc 打印的文本,优先按嵌套消息显示。 不勾选:JSON 里不属于该消息类型的键会让编码停止,报出行列号,有相近字段名时给出建议。勾选:这些键被跳过并列在说明里,Schema 中没有定义的枚举名也被跳过。

可粘贴十六进制(可带空格、换行、冒号和 0x 前缀)、Base64(标准或 URL 安全,有无填充都行,也可以是 data: URL)、转义字符串(如 Python 字节串或 protoc 的八进制转义),或 -128 到 255 的字节值列表。输入即解码。“打开文件”或把文件拖到框上,可载入 2 MB 以内的二进制文件,以十六进制显示。
所选消息类型的 ProtoJSON,输入即编码。键可以用字段的 JSON 名,也可以用 .proto 名。整数可写成数字或字符串,枚举可写名称或数值,bytes 用 Base64。出错时给出行列号。
提供字段名的 .proto 源码。“二进制 → JSON”可不填,这时字段显示为编号;另外两种模式必须填。它 import 的文件用“添加 .proto 文件”加入,或拖到框上。google/protobuf 的知名类型 any、duration、empty、field_mask、struct、timestamp、wrappers 已内置。不能载入编译后的 descriptor set,扩展 descriptor.proto 的自定义选项会被忽略。
输出
  
示例、说明与常见问题 带实际输出的示例、与同类工具的差别,以及常见问题。

示例:接口返回的雪花 ID

下面是一个用户服务的回包定义,id 是 64 位雪花 ID:

syntax = "proto3";

package api.user.v1;

message GetUserReply {
  int64 id = 1;
  string nickname = 2;
  int32 level = 3;
  bool vip = 4;
  repeated string tags = 5;
  Profile profile = 6;
}

message Profile {
  string city = 1;
}

抓到的 18 字节是 08 fb 80 dc 97 de e9 dd b2 19 12 06 e5 b0 8f e7 8e 8b。按 api.user.v1.GetUserReply 解码:

{
  "id": "1830000000000000123",
  "nickname": "小王"
}

id 是字符串,这是 ProtoJSON 格式 对 64 位整数的规定。如果后端把它写成 JSON 数字,前端 JSON.parse 得到的是 1830000000000000000,末尾三位已经变了。

level、vip、tags 没有出现,因为它们是默认值。如果服务端用 Go 框架 Kratos v2,它的 JSON 编解码器(v2.8.4 的 encoding/json/json.go)调用 protojson 并设置了 EmitUnpopulated: true,接口会输出这些字段。勾选“输出默认值字段”可以对照:

{
  "id": "1830000000000000123",
  "nickname": "小王",
  "level": 0,
  "vip": false,
  "tags": []
}

区别只有一处:protojson 的 EmitUnpopulated 会把未设置的消息字段写成 "profile": null,本工具的选项与 protojson 的 EmitDefaultValues、Python 的 always_print_fields_with_no_presence 一致,不输出它。

示例:手里没有 .proto

把 Schema 清空,原始视图选“JSON,附其他解读”,同样的字节变成:

{
  "1": {
    "uint64": "1830000000000000123",
    "sint64": "-915000000000000062"
  },
  "2": "小王"
}

线路格式里 varint 不带类型,同一组字节按 int64 读是正数,按 sint64(zigzag 编码)读就是负数。字段 2 是合法 UTF-8 文本,直接显示为字符串。选“protoc —decode_raw”视图,输出与 protoc --decode_raw 逐字相同,中文会显示成八进制转义。

示例:JSON 编码回二进制,带多余字段

联调时前端多传了一个 avatar_url:

{"id": "1830000000000000123", "nickname": "小王", "avatar_url": "https://example.com/a.png"}

在“JSON → 二进制”中直接报错,并给出位置:

api.user.v1.GetUserReply(第 1 行第 49 列):api.user.v1.GetUserReply 没有字段“avatar_url”。

Kratos v2 的反序列化设置了 DiscardUnknown: true,服务端会静默丢掉这个字段。勾选“忽略未知字段”得到同样的结果,说明里会写明忽略了哪个字段:

08 fb 80 dc 97 de e9 dd b2 19 12 06 e5 b0 8f e7 8e 8b

编码结果与抓到的字节完全一致。字段名写 nickname、枚举写名称或数字、int64 写字符串或数字都可以;输出可选十六进制、Base64、Python 字节串、C 数组,也可加 gRPC 帧头或下载为 .bin。

与其他在线工具的区别

2026-10-02 用本页英文版的订单示例(含 Timestamp 与超过 2^53 的 int64)实测。365 工具箱(toolbox365.cn)和 codertools.net 都用 protobufjs 解析 .proto:带 import "google/protobuf/timestamp.proto" 时,365 工具箱报“no such Type or Enum ‘google.protobuf.Timestamp’”,codertools 的消息类型列表为空;去掉 Timestamp 字段后,两者都把 order_id 输出成 "9007199254740992"(比真实值小 1),字段名保持下划线写法。365 工具箱的无 Schema 模式数值准确,并列出多种解读,但粘贴带 gRPC 帧头的数据时报“偏移 1 处 field number 为 0”,需要手工去掉前 5 字节。以上工具都没有把数据发到服务器。

限制

  • 只接受 .proto 源文件。protoc --descriptor_set_out 生成的描述符集合和文本格式消息都不能载入。内置的 import 只有 any、duration、empty、field_mask、struct、timestamp、wrappers;google/api/annotations.proto 等其他文件里如果有用到的类型,需要手动添加。扩展 descriptor.proto 的自定义选项会被忽略,选项不影响字节。
  • 未知字段不进 JSON。说明里列出编号、线路类型和字节位置,并给出能无未知字段解码的消息类型。
  • 类型选错也可能“成功”。二进制不带类型名,选错类型时常会解出奇怪的值,注意说明里的未知字段提示。
  • 嵌套最多 100 层,打开的文件不超过 2 MB;压缩帧只支持 gzip。
  • 支持 proto2 与 editions 2023/2024:组、required、封闭枚举、扩展("[pkg.ext]")、字段存在性、packed 与 expanded、delimited 消息。proto3 的 string 如果不是合法 UTF-8 会报错并给出字节位置,二进制数据应改用 bytes。

相关工具:用 HAR 文件分析器 查看抓包,用 Base64 编码 / 解码 转换载荷,用 JSON Schema 验证器 检查 JSON。

FAQ

没有 .proto 文件能解析吗?

能。Schema 留空时按 protoc --decode_raw 的方式解码,输出字段编号、数字、字符串和嵌套消息。字段名、枚举名、有符号和 64 位类型以及 Timestamp 这类知名类型需要 .proto,因为二进制里没有这些信息。

为什么 int64 输出成字符串?

ProtoJSON 规定 int64、uint64、sint64、fixed64、sfixed64 写成十进制字符串。JavaScript 把 JSON 数字读成 double,超过 2^53 就会丢位,雪花 ID 1830000000000000123 会变成 1830000000000000000。本工具用 BigInt 解码 64 位字段,数字一位不丢。

输出里为什么少了某些字段?

ProtoJSON 不输出取默认值(0、空字符串、false、枚举第一个值)的 proto3 普通字段。勾选“输出默认值字段”即可显示。字段编号不在 Schema 里的未知字段无法写进 ProtoJSON,“说明”里会逐个列出编号和字节位置。

gRPC 抓包数据怎么解?

直接粘贴。gRPC 帧选“自动”时,工具会去掉每条消息前 5 字节的帧头,逐条解码;gRPC-Web 的 trailers 帧显示在说明里,压缩标志为 01 的帧会先用 gzip 解压。

数据会上传吗?

不会。解析、解码和编码都在浏览器里完成。页面只保存选项,不保存 Schema、字节或 JSON。