Appearance
服务间通信里的 RPC 与 REST:概念解析、核心区别与选型策略
更新: 8/23/2026 字数: 0 字 时长: 0 分钟
一、先从一个全栈开发者的真实困惑说起
现在的 Web 应用早已不是"一个前端 + 一个后端"那么简单。业务一大,后端拆成了用户、订单、支付、商品一堆服务;前端也搞起了微前端;你的 Node.js BFF 层夹在中间,既要对接浏览器,又要调用一堆后端服务。
于是你开始纠结这些问题:
- 后端给的接口,有的是清爽的
GET /users/123,有的却是POST /invokeUserService,body 里塞一个method: "getUser"——这俩风格为啥差这么多? - 团队要新建一个内部服务,有人说用 REST,有人说上 gRPC,还有人提 GraphQL——到底该怎么选?
- 前端调后端用 REST 很顺手,可后端说"服务之间调用我们用 RPC,快"——RPC 到底快在哪?
这些困惑的核心,就是两种主流的服务间通信风格:RPC 和 REST。搞懂它们,你才能在服务集成、接口设计、技术选型时做出靠谱判断。这篇文章站在前端/JS 全栈视角,把它们讲透。
二、基础概念:RPC 和 REST 到底是什么
2.1 RPC:像调用本地函数一样调用远程服务
RPC(Remote Procedure Call,远程过程调用) 的核心理念是:让你调用一个远程服务器上的方法,就像调用本地函数一样自然。
用前端能秒懂的比喻:
你在代码里写
const user = await getUser(123),感觉是在调本地函数;但实际上getUser是另一台服务器上的方法。RPC 框架帮你把"参数打包 → 网络传输 → 远程执行 → 结果传回"这一整套藏在背后,你几乎无感。
它面向"动作/方法":关注的是"我要调用哪个方法、传什么参数",而不是"我要操作哪个资源"。RPC 起源很早(远早于 Web),在企业内部服务、高性能后端系统中广泛使用。典型实现有 gRPC、Thrift、Dubbo,以及 JS 生态里的 JSON-RPC。
2.2 REST:一切皆资源,用 HTTP 动词操作
REST(Representational State Transfer,表述性状态转移) 是一种基于 HTTP 的架构风格。它的核心理念是:把一切都抽象成"资源",用统一的 HTTP 动词去操作它们。
用点菜的比喻:
后端的数据(用户、订单、商品)都是"菜品"(资源),每个资源有一个地址(URL,如
/users/123)。你不用关心"调哪个方法",只需用标准动词说明你想干什么:GET获取、POST新建、PUT修改、DELETE删除。就像看着菜单点菜,标准而直观。
它面向"资源":关注"我要操作哪个资源"。REST 诞生于 Web 时代,天然基于 HTTP,是前后端交互、对外开放 API 的事实标准。


三、技术原理对比:通信模型、数据格式与接口风格
3.1 接口设计风格对照
同样是"获取用户信息",两种风格长这样:
javascript
// —— REST 风格:面向资源,动词由 HTTP method 表达 ——
// GET /users/123 获取用户
// POST /users 新建用户
// PUT /users/123 更新用户
// DELETE /users/123 删除用户
const user = await fetch('/users/123').then(r => r.json());
// —— RPC 风格:面向方法,动作写在方法名里 ——
// POST /rpc { "method": "getUser", "params": { "id": 123 } }
const user = await fetch('/rpc', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ method: 'getUser', params: { id: 123 } }),
}).then(r => r.json());看出区别了吗?REST 靠 URL + HTTP 动词表达意图;RPC 靠方法名 + 参数表达意图。
3.2 Node.js 实现示例
REST 服务端(Express):
javascript
const express = require('express');
const app = express();
app.use(express.json());
// 资源:users
app.get('/users/:id', (req, res) => res.json({ id: req.params.id, name: 'Alice' }));
app.post('/users', (req, res) => res.status(201).json({ id: 1, ...req.body }));
app.delete('/users/:id', (req, res) => res.status(204).end());
app.listen(3000);RPC 服务端(JSON-RPC 风格,极简演示):
javascript
const express = require('express');
const app = express();
app.use(express.json());
// 所有调用打到同一个端点,靠 method 分发
const methods = {
getUser: ({ id }) => ({ id, name: 'Alice' }),
createUser: ({ name }) => ({ id: 1, name }),
};
app.post('/rpc', (req, res) => {
const { method, params } = req.body;
const fn = methods[method];
if (!fn) return res.json({ error: 'method not found' });
res.json({ result: fn(params) });
});
app.listen(3000);gRPC(高性能 RPC 的代表) 则更进一步:用 .proto 文件定义接口(强类型契约),数据用 Protobuf 二进制编码,基于 HTTP/2 传输:
protobuf
// user.proto —— 接口契约
service UserService {
rpc GetUser (GetUserRequest) returns (User);
}
message GetUserRequest { int32 id = 1; }
message User { int32 id = 1; string name = 2; }javascript
// Node.js gRPC 客户端调用起来就像本地方法
client.getUser({ id: 123 }, (err, user) => {
console.log(user.name); // 感觉不到这是一次网络调用
});3.3 数据格式
- REST:通常用 JSON,人类可读、浏览器/前端天然友好、易调试(F12 直接看)。
- RPC:可用 JSON(如 JSON-RPC),但高性能场景多用 Protobuf 等二进制格式,体积小、序列化快,但不可读、需要工具解析。
四、核心区别:一张表看懂
| 对比维度 | REST | RPC(以 gRPC 为例) |
|---|---|---|
| 设计理念 | 面向资源(名词 + HTTP 动词) | 面向方法/动作(调远程函数) |
| 传输协议 | HTTP/1.1 为主 | 常基于 HTTP/2(gRPC) |
| 数据格式 | JSON(文本,可读) | Protobuf 等二进制(高效,不可读) |
| 性能 | 一般,文本解析有开销 | 高,二进制 + 多路复用,延迟低 |
| 可读性/调试 | 好,浏览器/curl 直接调 | 差,需专用工具 |
| 浏览器直接调用 | 原生支持 | 需 gRPC-Web 等中间层 |
| 接口契约 | 靠文档约定(如 OpenAPI) | 强类型契约(.proto),自动生成代码 |
| 松耦合程度 | 高,前后端独立演进 | 相对紧,依赖共享契约 |
| 典型场景 | 对外开放 API、前后端交互 | 内部微服务间高性能调用 |
一句话记忆:REST 重"通用与可读",RPC 重"性能与效率"。
五、选型决策:什么时候用哪个?

5.1 决策框架(四个关键问题)
5.2 结合前端/全栈场景的具体建议
- 前后端数据交互 / 对外 API → REST。浏览器友好、易调试、生态成熟,这是默认选择。
- Node.js 服务之间、微服务内部高频调用 → gRPC/RPC。性能和强类型契约优势明显。
- 前端页面需要聚合多个数据源、字段按需获取 → GraphQL(见下节)。
- 需要实时性(聊天、通知、协同、行情) → WebSocket。
- 微前端子应用间通信:这属于浏览器内通信,通常用
postMessage、自定义事件、共享状态,而非 RPC/REST(后者是跨网络的服务通信,别混淆)。
六、拓展:GraphQL、gRPC、WebSocket 与 API 网关

6.1 GraphQL:前端按需取数的利器
REST 常有两个痛点:过度获取(接口返回一堆你不需要的字段)和获取不足(一个页面要调好几个接口拼数据)。GraphQL 让前端自己声明要哪些字段,一个请求精确拿到所需数据:
javascript
// 前端只要 name 和最近 3 个订单的金额,一次拿全
query {
user(id: 123) {
name
orders(last: 3) { amount }
}
}它与 REST 是"风格之争",常用于前端与 BFF 层之间;底层数据仍可能来自 REST 或 RPC 服务。
6.2 gRPC:RPC 的高性能现代实现
gRPC 是 RPC 思想的现代高性能落地:HTTP/2 多路复用、Protobuf 二进制、支持双向流。内部微服务间通信的热门选择。注意:浏览器不能直接调 gRPC,需 gRPC-Web 代理转换,所以它极少直接面向前端。
6.3 WebSocket:双向实时通信
REST/RPC 本质是"请求-响应"(客户端问一句,服务端答一句)。而 WebSocket 建立长连接,支持服务端主动推送,适合聊天、实时通知、多人协同、行情推送等场景。它和 REST/RPC 不是替代关系,而是互补——大部分数据用 REST,实时部分用 WebSocket。
6.4 API 网关:把这些通信方式"编排"起来
在真实架构里,对外用 REST/GraphQL、对内用 RPC/gRPC 是常见分层。API 网关就是这个分层的关键枢纽:它对前端暴露统一的 REST 入口,做鉴权、限流、路由,再在内部把请求转发(或转换协议)到后端的 gRPC 微服务。

七、技术选型速查清单与最佳实践
场景速查表
| 场景 | 推荐方案 |
|---|---|
| 前后端数据交互 | REST(默认) |
| 对外开放 API | REST(生态/文档/兼容性最佳) |
| 内部微服务高频调用 | gRPC/RPC |
| 前端聚合多数据源、字段灵活 | GraphQL |
| 实时消息/通知/协同 | WebSocket |
| 浏览器需调用 gRPC 服务 | gRPC-Web 或经 网关转 REST |
| 微前端子应用间通信 | postMessage / 共享状态(非 RPC/REST) |
最佳实践建议
- [ ] 对外一律 REST:兼容性、可调试性、生态压倒一切;不要为了炫技让前端直连 gRPC。
- [ ] 对内可上 gRPC:内部高频服务调用,用强类型契约 + 二进制换性能。
- [ ] REST 接口遵循规范:名词复数资源、正确用 HTTP 动词和状态码(
200/201/204/400/401/404)。 - [ ] 契约先行:REST 用 OpenAPI/Swagger,gRPC 用
.proto,前后端按契约并行开发。 - [ ] 实时需求叠加 WebSocket,而不是用轮询硬扛。
- [ ] 用 API 网关做统一入口,屏蔽内部通信方式,前端只需对接一套 REST。
- [ ] 别过度设计:小项目 REST 一把梭,等真有性能瓶颈或明确需求再引入 gRPC/GraphQL。
八、总结
REST 面向资源、通用可读,是前后端交互和对外 API 的默认选择;RPC(尤其 gRPC)面向方法、高性能,是内部微服务高频调用的利器。现实架构常常"对外 REST、对内 RPC",再用 API 网关把它们编排统一——选型的关键不是谁更先进,而是谁更贴合你的调用场景。