JSON 与 Protocol Buffers 在 Go 中:网络通信应使用哪种?

发布: (2026年1月16日 GMT+8 10:38)
10 min read
原文: Dev.to

Source: Dev.to

(请提供需要翻译的正文内容,我将为您翻译成简体中文。)

介绍

如果你正在构建 API 或微服务,可能已经碰到过 数据序列化——把结构体转换成可以在网络中快速传输并在另一端完整恢复的形式。这就像为旅行打包行李:你希望它紧凑、可靠且易于拆解。

功能JSONProtobuf
格式文本,可读性强二进制,紧凑
模式灵活,无需模式严格,预定义
性能尚可超快
适用场景快速原型、APIgRPC,高性能

JSON 是友好、可读性强的选择,而 Protobuf 则是高性能的二进制“跑车”。哪一个更适合你的项目?

受众 – 具备 1–2 年经验的 Go 开发者,想要提升网络通信能力。

我们将深入探讨 JSON 与 Protobuf,比较它们的优势与劣势,并提供实用的 Go 代码帮助你做出决定。无论你是构建 REST API 还是 gRPC 微服务,阅读完本文后,你都能获得清晰的洞见和技巧,让你的服务更快、更可靠。让我们开始吧!

什么是数据序列化?

序列化是一种将 Go 结构体转换为可以在网络上传输或存储的格式(如字节流),然后在另一端再转换回结构体的技术。可以把它看作是把你的数据翻译成一种通用语言,让不同服务之间能够相互交流。

在 Go 中,序列化用于:

  • REST API – 在前端和后端之间发送 JSON。
  • gRPC 微服务 – 使用 Protobuf 实现超高速通信。
  • 消息队列 – 为 Kafka 或 RabbitMQ 序列化数据。
  • 数据库交互 – 保存和检索结构化数据。

Go 的静态类型和简洁的标准库让序列化变得轻而易举,但选择合适的格式——JSON 还是 Protobuf——可能会决定你的应用性能成败。

Go 中的 JSON:简洁友好

JSON 就像咖啡店里的闲聊——易于理解,人人都能上手。它是 REST API 的首选,因为可读性强、跨平台支持广泛,并且在 Go 中使用 encoding/json 包非常简单。

为什么 JSON 很棒

  • 可读性强 – 直接查看 JSON 数据即可,无需工具,调试时非常方便。
  • 通用性 – 所有语言和平台都支持 JSON,适合混合技术栈。
  • 灵活性 – 没有严格的模式约束,能够快速迭代而无需频繁修改契约。

JSON 实例

package main

import (
	"encoding/json"
	"net/http"
)

// User struct for JSON serialization
type User struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

func handleUser(w http.ResponseWriter, r *http.Request) {
	var user User
	// Parse JSON request
	if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
		http.Error(w, "Bad JSON", http.StatusBadRequest)
		return
	}
	// Send JSON response
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(user)
}

func main() {
	http.HandleFunc("/user", handleUser)
	http.ListenAndServe(":8080", nil)
}

关键技巧

  • 使用 json:"field" 标签将结构体字段映射到 JSON 键。
  • 始终检查解码错误,以避免崩溃。
  • 为了让客户端正确处理,设置 Content-Type: application/json

适用场景

  • REST API – 适合对可读性有要求的 Web 应用。
  • 配置文件 – 易于编辑和解析。
  • 第三方 API – JSON 的通用支持让集成变得轻而易举。

注意事项

  • 空指针 – 未初始化的字段会序列化为 null。使用 omitempty(例如 json:"field,omitempty")可以跳过它们。
  • 大型 JSON 文件 – 解析巨大的 JSON 可能占用大量内存。此时可使用 json.Decoder 进行流式处理。
  • 键名不匹配 – 确保 JSON 键与结构体标签一致,避免解析失败。

JSON 的简洁性使其非常适合快速原型开发或小型项目,但在处理大规模数据时可能会出现性能瓶颈。

Go 语言中的 Protocol Buffers:快速且强大

Protobuf 就像高速快递服务——紧凑、高效、专为性能而生。由 Google 开发,使用二进制格式和严格的 schema,因而成为 gRPC 微服务和高吞吐系统的首选。

为什么 Protobuf 出彩

  • 速度 – 二进制序列化比 JSON 快 5–10 倍
  • 体积 – 数据大小通常 小 50–80 %,节省带宽。
  • 强类型 Schema.proto 文件强制数据契约,便于团队协作。

Protobuf 实战

user.proto

syntax = "proto3";

package user;
option go_package = "./user";

message User {
  int32 id   = 1;
  string name = 2;
}

message UserRequest {
  int32 id = 1;
}

service UserService {
  rpc GetUser (UserRequest) returns (User);
}

server.go

package main

import (
	"context"
	"log"
	"net"

	"google.golang.org/grpc"
	pb "path/to/user"
)

type userService struct {
	pb.UnimplementedUserServiceServer
}

func (s *userService) GetUser(ctx context.Context, req *pb.UserRequest) (*pb.User, error) {
	return &pb.User{Id: req.Id, Name: "Alice"}, nil
}

func main() {
	lis, err := net.Listen("tcp", ":50051")
	if err != nil {
		log.Fatalf("Failed to listen: %v", err)
	}
	grpcServer := grpc.NewServer()
	pb.RegisterUserServiceServer(grpcServer, &userService{})
	log.Println("gRPC server running on :50051")
	grpcServer.Serve(lis)
}

关键技巧

  • 为数据一致性定义清晰的 .proto schema。
  • 使用 protoc-gen-goprotoc-gen-go-grpc 进行代码生成。
  • 仅在需要手动修补时才将生成的代码纳入版本控制;否则应在构建流水线中重新生成。

JSON vs. Protobuf: Quick Decision Guide

ConcernJSONProtobuf
人类可读性✅ 易于阅读和编辑❌ 二进制(需要工具)
性能✅ 对大多数 API 足够✅ 对高吞吐量更优
消息大小✅ 较大(文本)✅ 较小(二进制)
模式演进✅ 灵活(无模式)✅ 严格,但支持向后兼容的更改
工具与生态✅ 内置 encoding/jsonprotocgrpc-go
互操作性✅ 在任何地方都能工作✅ 在任何地方都能工作(使用生成的代码)
  • 选择 JSON 当你需要快速迭代、可供人类阅读的负载,或正在构建公共 REST 接口时。
  • 选择 Protobuf 当你需要最高性能、严格的契约,或正在构建内部 gRPC 服务时。

实用技巧:混合使用两者

  1. 在 gRPC 服务前面暴露一个 JSON 网关。使用 grpc‑gateway 等工具将 HTTP/JSON 转换为 gRPC/Protobuf。
  2. .proto 文件进行版本管理,并将其放在专用仓库中;在 CI 中生成 Go 代码。
  3. 基准测试 两种格式,使用真实负载(go test -bench=.)后再决定采用哪一种。
  4. 避免过度优化:对于许多业务逻辑 API 来说,JSON 的开销相对于数据库延迟可以忽略不计。

TL;DR

  • JSON = 简单、易读,适合公共 API 和快速原型开发。
  • Protobuf = 高速、紧凑、严格的模式——适用于内部服务、gRPC 和大流量场景。

选择与您的性能需求、团队工作流和生态系统约束相匹配的格式。祝编码愉快!

何时使用 Protobuf

  • 与 gRPC 配合,实现低延迟通信。

gRPC 微服务 – 适用于快速、强类型的服务间调用。
高吞吐系统 – 非常适合日志记录或实时数据。
跨团队项目 – 架构保持所有人步调一致。

注意事项

  • 学习曲线.proto 文件和 protoc 设置需要时间来掌握。
  • 兼容性 – 通过为已弃用的字段保留字段编号,避免破坏客户端。
  • 调试 – 二进制数据不可读。使用 protoc --decode 进行检查。

Resources to Keep You Going

Tools to Try

  • JSON – Go 的 encoding/json 包以及用于 API 测试的 Postman。
  • Protobuf – 使用 protoc 搭配 protoc-gen-goprotoc-gen-go-grpc 插件。
  • gRPC – 用于高速服务的 google.golang.org/grpc 包。

References

Open‑Source Gems

Join the Community

  • Dev.toX 上分享你的序列化技巧。
  • X 上与 Go 开发者交流,互换代码片段和想法。
Back to Blog

相关文章

阅读更多 »

Gin vs Spring Boot:详细比较

封面图片:Gin vs Spring Boot:详细比较 https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%...

Dev.to API 介绍

入门 - 登录你的 dev.to 账户。 - 前往 设置 → 账户。 - 向下滚动到 DEV API Keys 部分。 - 生成一个新密钥并将其复制到某处。