Appearance
API 风格对比
本章导读:REST 不是唯一的 API 风格。理解 RPC(含 gRPC/SOAP)、GraphQL、WebSocket 各自的取舍,你才能回答面试与架构评审中的高频问题:"为什么这个场景选 REST?"本章给出一张决策地图。
1. 四大流派速写
1.1 REST(资源导向)
- 契约单位:资源 + 统一接口(方法/状态码/媒体类型)。
- 客户端说"我要这个资源的这个表现",服务器执行并返回。
- 充分利用 HTTP 生态:缓存、代理、CDN、监控、安全网关。
1.2 RPC(动作导向,含 gRPC)
- 契约单位:方法签名。
PayOrder(orderId, amount)直接映射为一次远程调用。 - gRPC 用 Protobuf 强类型 + HTTP/2 多路复用,性能与代码生成能力极强。
- 传统 SOAP/WebService 是重量级前辈(WSDL),REST 正是作为它的"轻量反叛"而流行。
protobuf
service ArticleService {
rpc GetArticle(GetArticleRequest) returns (Article);
rpc PublishArticle(PublishArticleRequest) returns (google.protobuf.Empty);
}1.3 GraphQL(查询语言导向)
- 契约单位:类型系统 + 客户端驱动的查询。一个端点
POST /graphql,客户端精确声明要的字段。 - 解决 REST 两大痛点:over-fetching(返回多余字段)与 under-fetching(N+1 次请求拼装页面)。
graphql
query { article(id: 42) { title author { name } } }1.4 WebSocket / 消息流(推送导向)
- 全双工长连接,服务器主动推送。适合协作编辑、行情、聊天、多玩家游戏。
2. 逐维度对比
| 维度 | REST | RPC/gRPC | GraphQL | WebSocket |
|---|---|---|---|---|
| 接口语义 | 资源 + 标准方法 | 自定义方法 | 单端点 + 查询语言 | 消息帧 |
| 契约定义 | OpenAPI(弱类型可选) | proto IDL(强类型) | SDL 类型系统 | 无标准,自定义协议 |
| 缓存 | HTTP 缓存原生支持 | 不支持(需自建) | 请求体参与缓存键,难缓存 | 无 |
| 浏览器/代理友好 | ★★★★★ | ★★★(需 grpc-web) | ★★★★(本质是 POST) | ★★ |
| 性能(内网服务间) | 好 | 极佳(二进制 + 多路复用 + 流) | 一般(查询解析开销) | 极佳 |
| 灵活取数/聚合 | 弱(多资源要多次请求) | 弱(方法固定) | 极强 | — |
| 移动端弱网优化空间 | 中 | 高 | 高(按需取字段) | — |
| 学习/工具生态 | 最成熟 | 微服务领域成熟 | 增长中 | 成熟 |
| 权限控制粒度 | 端点 + 字段级需自研 | 方法级 | 字段级 resolver,天然细 | 自研 |
3. 选型决策地图
是对外公开/第三方集成的 API 吗?
├─ 是 → REST(生态最大、网关友好、OAuth 标准链路)
└─ 否(内部系统)
├─ 高频服务间调用、延迟敏感、需要双向流?
│ └─ 是 → gRPC
├─ 页面数据形态多变、由前端团队自主迭代?
│ └─ 是 → GraphQL(或 REST + BFF 层)
├─ 服务器需主动实时推送?
│ └─ 是 → WebSocket / SSE(REST 管理资源 + SSE 推进度是常见组合)
└─ 默认 → REST:CRUD 主导、资源模型稳定的业务系统混合是常态:
- 支付回调、转账确认等"过程性"操作,REST 社区也允许动词端点(
POST /articles/42/publish)或任务子资源——纯粹的"万物皆名词"在工程上并非必须。 - 大厂典型架构:对外 REST 网关 → 内部 gRPC 微服务 → 个别 GraphQL BFF。REST 的"对外契约"地位并不因内部选型而动摇。
4. REST 的常见批评(诚实面对)
| 批评 | 回应 |
|---|---|
| N+1 请求:文章 + 作者 + 评论要 3 次请求 | 用 ?expand=author,comments(字段扩展)或 BFF 聚合;GraphQL 确实更优 |
| over-fetching:接口返回整个资源 | 提供 ?fields=title,id 稀疏集(Sparse Fieldsets,JSON:API 概念) |
| 批量写操作别扭(无批量 POST 标准) | 设计批量端点 POST /articles:batchCreate(Google AIP 风格)或作业资源,见批量操作设计 |
| 复杂流程/长事务表达弱 | 把流程建模为资源(/jobs/{id} + 状态轮询/SSE),见实战篇 |
| 规范只给原则不给细节,团队各写各的 | 正因如此才需要本教程第 03 篇"设计规范"与 OpenAPI 治理 |
5. 一个务实的结论
- 资源稳定的业务数据(用户、订单、文章)→ REST 建模几乎总是正确答案。
- 动作密集、计算服务(转码、AI 推理)→ 把"任务"做成资源(
POST /jobs+GET /jobs/{id}),仍是 REST 的扩展而非抛弃。 - 强类型内部 RPC 与 REST 外部契约可以并存,不必二选一。
6. 本章小结
- REST 的核心竞争力不是性能,而是统一接口带来的协议级生态(缓存/网关/安全/可观测性)。
- 选型依据是"数据形态由谁决定":服务端决定→REST;客户端决定→GraphQL;双方高频互推→WebSocket。
- REST 的缺陷有成熟的模式化补救(expand 参数、稀疏字段、作业资源),学完后续章节即可落地。
7. 下一步
入门篇到此结束。从下一章开始,我们把 REST 拆成可执行的设计动作——先解决"什么是资源、怎么划分" → 资源与资源层次