Week 3 · Chapter 2 · gRPC 与 Protobuf

复习难度:⭐⭐⭐ | 预计时长:2-3小时 | 重点程度:中


为什么选 gRPC

HTTP/1.1 → 队头阻塞(同一TCP连接只能串行请求)
HTTP/2 → 多路复用(一个TCP连接并行多个请求)
gRPC → 基于 HTTP/2 + Protobuf(二进制序列化,比 JSON 小 3-6 倍)

你的 IAM 系统用 gRPC-Gateway 同时暴露 HTTP 和 gRPC 接口。


Protobuf 基本语法

syntax = "proto3";

package user;

service UserService {
  rpc GetUser(GetUserRequest) returns (UserResponse);
  rpc ListUsers(ListUsersRequest) returns (stream UserResponse); // 服务端流
}

message GetUserRequest {
  string user_id = 1;  // 字段编号,不是字段名
  int32 page_size = 2 [default = 10];
}

message UserResponse {
  string id = 1;
  string name = 2;
  string email = 3;
  map<string, string> metadata = 4;  // map 类型
  repeated string roles = 5;         // 数组
}

注意:字段编号是协议升级时唯一稳定的标识,改字段名不影响序列化。


gRPC 拦截器

// unary interceptor( unary = 单次请求响应)
func AuthInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    // 从 metadata 取 token
    md, ok := metadata.FromIncomingContext(ctx)
    if !ok { return nil, status.Error(codes.Unauthenticated, "no metadata") }

    token := md["authorization"]
    if !validateToken(token) { return nil, status.Error(codes.Unauthenticated, "invalid token") }

    return handler(ctx, req)
}

服务端流和客户端流拦截器写法类似,用 grpc.StreamServerInterceptor


面试重点

Q:gRPC 和 REST 的区别?

① 序列化:Protobuf vs JSON(二进制 vs 文本) ② 传输协议:HTTP/2 vs HTTP/1.1 ③ 接口定义:.proto 文件强类型 vs OpenAPI 弱类型 ④ 流支持:原生支持服务端/客户端/双向流

Q:gRPC 的缺点?

① 调试不如 HTTP/REST 方便(不能用浏览器直接测试) ② 穿透防火墙不如 HTTP(有些代理不认识) ③ 学习成本比 REST 高

Q:你为什么选 gRPC-Gateway?

内部服务用 gRPC 高性能,外部系统(如审批回调)用 HTTP 方便接入,一次定义同时暴露两种接口。