REST | GraphQL | gRPC | tRPC
REST api
REST(Representational State Transfer)
是一种软件架构风格,用于设计网络应用程序的 API。
REST API 就是遵循 REST 原则的 Web 接口,通常基于 HTTP
协议。
✅ 核心思想:把一切看作“资源”(Resource),通过标准 HTTP 方法对资源进行操作。
REST 的六大约束(简化版理解)
| 约束 | 含义 | 举例 |
|---|---|---|
| 统一接口 | 所有操作通过标准 HTTP 方法(GET/POST/PUT/DELETE) | /books 表示“图书资源” |
| 无状态 | 服务器不保存客户端状态,每次请求必须包含全部信息 | 用 Token 认证,而不是 Session |
| 可缓存 | 响应应标明是否可缓存 | GET 请求通常可缓存 |
| 分层系统 | 客户端无需知道是否直接连服务器(可经过代理、网关) | Nginx 反向代理 FastAPI |
| 按需代码(可选) | 可返回可执行代码(如 JS) | 较少用 |
| 资源标识 | 每个资源有唯一 URI | /books/123 唯一标识 ID 为 123 的书 |
常用 HTTP 方法与语义
| 方法 | 含义 | 幂等性 | 安全性 | 例子 |
|---|---|---|---|---|
GET |
获取资源 | ✅ 是 | ✅ 是 | 获取所有图书 |
POST |
创建资源 | ❌ 否 | ❌ 否 | 新增一本图书 |
PUT |
完整更新资源 | ✅ 是 | ❌ 否 | 替换 ID 为 123 的图书全部信息 |
PATCH |
部分更新资源 | ❌ 否 | ❌ 否 | 只修改图书的标题 |
DELETE |
删除资源 | ✅ 是 | ❌ 否 | 删除 ID 为 123 的图书 |
🔔 幂等性:多次执行结果相同(如 DELETE /books/123,删一次和删十次效果一样)
🔔 安全性:不改变服务器状态(GET 是安全的,POST 不是)
举个 FastAPI 的完整例子
假设你正在开发图书管理系统,下面是典型 REST API:
1 | # main.py |
启动后,你就可以通过:
GET /books→ 获取所有书POST /books→ 创建新书GET /books/1→ 获取 ID=1 的书PUT /books/1→ 完全替换 ID=1 的书DELETE /books/1→ 删除 ID=1 的书
REST API 常见响应格式(JSON)
1 | // 成功创建 |
HTTP 状态码也很关键:
| 状态码 | 含义 |
|---|---|
| 200 | OK(GET 成功) |
| 201 | Created(POST 成功) |
| 204 | No Content(DELETE 成功,无返回体) |
| 400 | Bad Request(参数错误) |
| 404 | Not Found(资源不存在) |
| 500 | Internal Server Error |
GraphQL
GraphQL 是由 Facebook 开发的一种 API 查询语言 和 运行时,用于客户端精确声明它需要什么数据,服务器则按需返回这些数据。
✅ 核心理念:“客户端要什么,服务端就给什么”,避免 REST 中常见的“过载”或“多次请求”问题。
场景
你想获取用户 ID=1 的 姓名 和他最新的 两篇文章标题
🔹 REST 方式(你熟悉的方式)
1 | GET /users/1 → 返回 {id, name, email, avatar, ...} (可能含不需要的 email/avatar) |
→ 2 次请求 + 数据冗余
🔸 GraphQL 方式
客户端发送一个 查询(Query):
1 | query { |
服务器返回:
1 | { |
→ 1 次请求 + 精确数据
1. Schema(类型系统)
定义 API 的能力:有哪些类型?有哪些字段?
1 | type User { |
2. Query(查询)
客户端请求数据(类似 REST 的 GET)
3. Mutation(变更)
客户端修改数据(类似 REST 的 POST/PUT/DELETE)
1 | mutation { |
RPC
RPC(Remote Procedure Call) 是一种让程序调用另一个地址空间(通常是远程服务器)上的函数/过程,就像调用本地函数一样的机制。
✅ 核心思想:“像调用本地函数一样调用远程服务”
你不需要关心网络细节(HTTP、序列化等),框架会自动处理。
为什么有了 HTTP 还需要 RPC?
我们可以把 HTTP/REST 比作 “写信”,把 RPC 比作 “发电报”。
A. 数据包的大小(信封 vs. 代码)
- HTTP (REST+JSON): 为了让人看懂,JSON 极其啰嗦。
- 比如传递一个数字
1000,JSON 需要写成字段"balance": 1000。为了传这一个数,你得带上"balance"这个单词,还有大括号、冒号。这就像写信时要写满客套话。
- 比如传递一个数字
- RPC (Protobuf/二进制):
机器不需要看懂单词,它只需要知道位置。
- RPC 协议会约定:“第2个位置放余额”。传输时,直接发二进制的
1000即可。数据体积可以缩小 50%~80%。
- RPC 协议会约定:“第2个位置放余额”。传输时,直接发二进制的
B. 解析速度(阅读 vs. 直觉)
- HTTP: 服务器收到 JSON 后,CPU 需要一行行去“读”文本,把字符串转换成对象。这非常消耗 CPU 资源。
- RPC: 二进制数据到了服务器,几乎不需要转换,直接就能由计算机内存读取。解析速度比 JSON 快很多倍。
C. 约束力(口头约定 vs. 法律合同)
- HTTP: REST API 的文档通常写在网页上(比如 Swagger)。如果后端改了字段名,前端没注意,上线可能就崩了。这属于“弱约束”。
- RPC: 强依赖 IDL(接口定义语言)。在代码编译阶段,如果客户端和服务端定义的参数类型对不上,代码直接报错,编译不过。这大大减少了上线后的低级错误。
注意: 现代的 RPC(如 gRPC)其实底层往往也是基于 HTTP/2 协议传输的。所以准确地说,并不是“抛弃 HTTP 用 RPC”,而是“在 HTTP 之上通过 RPC 机制来优化传输效率”。
RPC 主要用于什么场景?
RPC 并不是为了取代 REST,而是为了在特定领域“称王”。
场景一:微服务架构的内部通信(这是绝对的主战场)
想象一个像淘宝或亚马逊这样的大型系统,一个“用户下单”的请求,在后台可能要触发 50 次 内部调用(查库存、算优惠、校验风控、写日志、通知物流…)。
- 如果全用 REST:
- 每次调用都要解析一遍 JSON,CPU 累死。
- 每次传输都带一堆冗余的 HTTP 头,网络堵死。
- 总延迟 = 50 次 HTTP 请求的累加,用户会感觉“卡顿”。
- 如果用 RPC:
- 二进制传输,极快。
- 内部带宽占用极低。
- 结论: 对外(给浏览器/App)用 REST,对内(服务器之间)用 RPC。
场景二:高频交易与实时系统
在股票交易、实时游戏同步等对延迟(Latency)极其敏感的场景。
- 每一毫秒都决定盈亏。RPC 省去了繁琐的 HTTP 报文头解析,能把延迟压榨到极限。
场景三:多语言混合开发 (Polyglot)
公司里,算法团队用 Python(搞 AI),后端团队用 Java(搞业务),数据团队用 Go。
- 使用 gRPC(Google 的 RPC 框架),只需要定义一份
.proto文件,就能自动生成 Python、Java、Go 的代码。这三个团队不需要互相通过文档扯皮,直接调用生成的代码即
RPC 调用流程
1 | sequenceDiagram |
对比 REST 的资源操作:
1 | sequenceDiagram |
gRPC:跨语言的通用翻译官
gRPC 是由 Google 开发并开源的高性能 RPC 框架。它是目前微服务架构中的事实标准。
核心特点:
- 基于 HTTP/2: 它利用 HTTP/2 的特性(如多路复用、头部压缩),传输效率极高。
- Protocol Buffers (Protobuf): 这是 gRPC
的灵魂。它不使用 JSON,而是使用 Google 发明的
.proto文件来定义接口和数据结构。 - 多语言支持 (Polyglot):这是它最大的杀手锏。
适用场景:
- 微服务架构: 几十个服务,有的用 Java 写,有的用 Python 写,需要互相通信。
- 移动端对接: 手机 App 与服务器通信(省流量、省电)。
tRPC:TypeScript 开发者的“心灵感应”
tRPC (TypeScript RPC) 是近年来在前端圈(特别是 React/Next.js 社区)爆火的库。
注意: tRPC 只能用于 TypeScript。如果你的后端是 Java 或 Go,那就不能用它。
核心特点:
- 端到端类型安全 (End-to-End Type Safety): 这是它存在的全部意义。
- 无代码生成 (No Code Gen): 不需要写
.proto文件,也不需要运行脚本生成代码。 - 基于标准 HTTP: 底层通常还是普通的 HTTP 请求,但写代码的感觉是 RPC。
适用场景:
- 全栈 TypeScript 项目: 比如使用 Next.js, Nuxt.js 等框架,前后端都在一个代码仓库(Monorepo)里。
- 中小型快速开发: 一个团队同时负责前后端,追求极致的开发速度。