参考:gRPC 方法、状态码与 proto 演进速查
基于 gRPC 1.71 / protobuf proto3 · 核于 2026-08
速查
- gRPC:Google 开源高性能 RPC,protobuf IDL + HTTP/2,跨 11+ 语言,CNCF 毕业项目(2018)。
- protobuf:二进制序列化,tag-length-value 编码,字段名不存只存字段号,比 JSON 小 20%~70%。
- HTTP/2:多路复用 + 二进制分帧 + HPACK + 双向流,是 gRPC 性能与流式调用的物理基础。
- 四种方法:Unary(一问一答)、Server Streaming(一请求多响应)、Client Streaming(多请求一响应)、Bidirectional(双向流)。
- Channel/Stub:Channel 是底层 HTTP/2 连接池(共享复用),Stub 是类型化客户端(由 proto 生成)。
- Deadline:客户端超时,一路传递,生产必设(不设是反模式)。
- metadata:HTTP/2 头部,键小写、不可
grpc-开头、二进制值键-bin结尾。 - 拦截器:客户端/服务端各 4 种(unary/server-stream/client-stream/bidi),用于 auth/log/metrics/trace。
- 状态码:17 个标准码,
grpc-status在 trailer,比 HTTP 语义精细。 - Connect:Buf 出品,一份 proto 出 gRPC/Connect/HTTP+JSON 三协议,浏览器原生无需 grpc-web。
一、四种服务方法速查
| 方法 | 请求 | 响应 | 客户端代码 | 服务端代码 | 场景 |
|---|---|---|---|---|---|
| Unary | 1 | 1 | stub.SayHello(req) → Promise<Resp> | async sayHello(req) → resp | 普通 API(90%) |
| Server Streaming | 1 | N | for await (const r of call) | while(...) yield r | 推送/分页/行情 |
| Client Streaming | N | 1 | call.write(...) × N → call.end() | for await (const r of call) | 批量上传/攒批 |
| Bidirectional | N | N | call.write/read 独立 | call.write/read 独立 | 聊天/协同/实时 |
- 顺序保证:同一 RPC 内,消息按发送顺序到达。
- 取消:客户端随时
call.cancel(),服务端通过 context 感知。
二、gRPC 状态码清单
| 码 | 名称 | 含义 | 对应 HTTP 类比 |
|---|---|---|---|
| 0 | OK | 成功 | 200 |
| 1 | CANCELLED | 客户端取消 | - |
| 2 | UNKNOWN | 未知错误 | 500 |
| 3 | INVALID_ARGUMENT | 参数非法 | 400 |
| 4 | DEADLINE_EXCEEDED | 超时 | 504 |
| 5 | NOT_FOUND | 资源不存在 | 404 |
| 6 | ALREADY_EXISTS | 已存在 | 409 |
| 7 | PERMISSION_DENIED | 无权限 | 403 |
| 8 | RESOURCE_EXHAUSTED | 资源耗尽(配额/限流) | 429 |
| 9 | FAILED_PRECONDITION | 前置条件不满足 | 400 |
| 10 | ABORTED | 并发冲突(可重试) | 409 |
| 11 | OUT_OF_RANGE | 超出范围 | 400 |
| 12 | UNIMPLEMENTED | 方法未实现 | 501 |
| 13 | INTERNAL | 内部错误 | 500 |
| 14 | UNAVAILABLE | 服务不可用(可重试) | 503 |
| 15 | DATA_LOSS | 数据丢失 | - |
| 16 | UNAUTHENTICATED | 未认证 | 401 |
- 可重试码(客户端可重试):
UNAVAILABLE、DEADLINE_EXCEEDED(部分场景)、ABORTED、RESOURCE_EXHAUSTED(限流)。 - 不可重试码:
INVALID_ARGUMENT、NOT_FOUND、PERMISSION_DENIED(重试也是错)。
三、proto3 演进规则
| 操作 | 是否安全 | 说明 |
|---|---|---|
| 新增字段 | ✅ | 旧客户端不传,新代码用默认值 |
| 删除字段 | ✅ | 必须 reserved N; 占号 |
| 改字段名 | ✅ | 按字段号解析,名无所谓 |
| 同 wire type 换类型 | ✅ | int32↔uint32、string↔bytes |
| 复用已删字段号 | ❌ | 旧数据被误读,破坏兼容 |
| 单值改 repeated | ❌ | wire type 语义冲突 |
| 改字段号 | ❌ | 等于删旧字段加新字段 |
| 改默认值 | ❌ | 默认值是语言规范定的,改不了 |
口诀:加字段随意、删字段 reserved、号不可复用、同 wire type 才能换类型。
四、拦截器场景与位置
| 场景 | 客户端拦截器 | 服务端拦截器 |
|---|---|---|
| 认证 | 注入 auth header | 验证 token(注意:客户端 call credentials 更合适) |
| 日志 | 记录请求/响应 | 记录调用 |
| 指标 | 记录耗时/QPS | 记录耗时/错误率 |
| 链路追踪 | 注入 traceparent | 开 span、关 span |
| 重试 | 失败自动重试 | - |
| 限流 | - | 拒绝超额请求 |
| 缓存 | 命中缓存直接返回 | - |
- 注意:拦截器只作用于单个 RPC 调用,管不了 TCP/TLS/端口——那是 ChannelOption 的活。
五、metadata 规则
| 规则 | 说明 |
|---|---|
| 键大小写 | 不敏感,建议全小写 |
| 键字符 | 字母、数字、-、_、. |
| 保留前缀 | grpc- 开头是框架保留(如 grpc-status、grpc-encoding) |
| ASCII 值键 | 普通 key(如 authorization) |
| 二进制值键 | 必须 -bin 结尾(如 trace-bin) |
六、gRPC over HTTP/2 速查
| 元素 | 值 |
|---|---|
:method | POST |
:path | /{package}.{Service}/{Method} |
:scheme | http / https |
content-type | application/grpc(+ +proto / +json) |
te | trailers(必需) |
grpc-encoding | identity / gzip / deflate / snappy |
grpc-status | 在 trailer(响应尾部) |
grpc-message | 错误消息(在 trailer) |
| 消息前缀 | 1B 压缩标志 + 4B 长度 + protobuf 体 |
七、易错点清单
- 「gRPC 就是 protobuf」:错。gRPC 是 RPC 框架(管连接/调用/流式/状态码),protobuf 是序列化格式(管消息编码)。gRPC 默认用 protobuf,但理论上能用 JSON(
application/grpc+json)。 - 「HTTP/2 多路复用就一定快」:不一定。单连接多路复用在高并发小消息场景最优;超大文件传输(单流占满带宽)反而不如多连接。gRPC 默认单 Channel,必要时开多 Channel 负载均衡。
- 「Unary 是流式的退化」:错。Unary 是独立的方法类型,有自己的调用流程和拦截器,不是「只发一条的流」。
- 「proto 加字段要删旧客户端」:错。protobuf 向后兼容——加字段,旧客户端不传新字段,新代码用默认值,零影响。
- 「字段号可以随便改」:错。字段号是 wire 编码的 key,改号等于删旧字段加新字段,破坏兼容。
- 「gRPC 状态码就是 HTTP 状态码」:错。gRPC 有 17 个独立状态码,
grpc-status在 trailer,语义和 HTTP 不同(如UNAVAILABLE=14不是 HTTP 503 的 1:1 映射)。 - 「浏览器可以直接调 gRPC」:错。浏览器 fetch 无法控制 HTTP/2 trailer 与伪头,必须用 grpc-web(代理)或 Connect(原生)。
- 「Deadline 只是客户端的事」:错。Deadline 一路传递——服务端 handler 能查到剩余时间(
context.deadline),据此决定是否提前返回,避免下游雪崩。 - **「metadata 键可以大写」」:技术上大小写不敏感,但规范是小写。且
grpc-前缀是框架保留,用户键不能用。 - 「Connect 替代了 gRPC」:错。Connect 是 gRPC 的现代化补充(浏览器/JSON 友好),但完全兼容标准 gRPC 客户端——一份 proto 同时服务 gRPC 和 Connect,不是替代关系。