文章目录
RPC 和 REST 的请求样式是什么样的
在比较这两种请求样式之前,让我们看看它们的样子。
HTTP 请求
RPC 和 REST 都使用HTTP协议,它是一种请求/响应协议。
一个基本的 HTTP 请求包括:
- 动词(method)
- 资源(endpoint)
每个 HTTP 动词:
- 都存在具体含义
- 是否存储幂等(如果使用该方法的多个相同请求对服务器的预期效果与单个此类请求的效果相同(则该请求方法被认为是“幂等的”。)
- 是否安全:如果请求方法定义的语义本质上是只读的,则它们被认为是“安全的”。
- 是否可缓存。
动词 | 含义 | 幂等性 | 安全性 | 可否缓存 |
---|---|---|---|---|
GET | 读取资源 | yes | yes | yes |
POST | 创建资源或触发数据处理过程 | no | no | 仅当响应包含明确的新信息时才可缓存 |
PUT | 完全更新现有资源或创建资源 | yes | no | no |
PATCH | 部分更新资源 | no | no | 仅当响应包含明确的新信息时才可缓存 |
DELETE | 删除资源 | yes | no | no |
上表仅显示了 RPC 和 REST API 常用的 HTTP 动词。
RPC:操作请求样式
该RPC缩写有很多含义和远程过程调用有多种形式。
在这篇文章中,当我谈论 RPC 时,我谈论的是WYGOPIAO: What You GET or POST Is An Operation。
使用这种类型的 RPC,您可以暴露接口以通过 HTTP 作为传输协议来操作数据。
据我所知,这种风格没有特别的规则,但一般来说:
- 资源(endpoint)包含您要调用的操作的名称。
- 这种类型的 API 通常只使用GET和POST的HTTP动词。
GET /someoperation?data=anId
POST /anotheroperation
{
"data":"anId";
"anotherdata":"another value"
}
人们如何在 GET 和 POST 之间做出选择?
- 对于那些稍微关心 HTTP 协议的人来说,这种类型的 API 倾向于将 GET 用于不修改任何内容的操作,而对于其他情况则使用 POST。
- 对于那些不太关心HTTP协议的人来说,这种类型的API在不需要太多参数的操作上倾向于使用GET,其他情况则使用POST。
- 那些真正不关心或者不考虑它的人通常随机选择 GET 和 POST 或始终使用 POST。
REST:资源请求风格
我不会详细解释什么是 REST,您可以阅读 Roy Fielding 的论文和The REST cookbook了解更多详细信息。
简而言之,重点放在这篇文章的问题上,使用 REST API,您将数据公开为资源,您可以使用正确的 HTTP 动词通过 HTTP 协议进行操作:
- 包含您操作的资源。
- 许多人使用 CRUD 类比来解释 REST 请求原则。HTTP 动词表示您想对该资源执行的操作(创建/读取/更新/删除)。
GET /someresources/anId
PUT /someresources/anId
{"anotherdata":"another value"}
例子
以下是我以 RPC 和 REST 方式呈现的一些CarBoN API请求:
操作 | RPC | REST |
---|---|---|
Signup | POST /signup | POST /persons |
Resign | POST /resign | DELETE /persons/1234 |
Read a person | GET /readPerson?personid=1234 | GET /persons/1234 |
Read a person’s items list | GET /readUsersItemsList?userid=1234 | GET /persons/1234/items |
Add an item to a person’s list | POST /addItemToUsersItemsList | POST /persons/1234/items |
Update an item | POST /modifyItem | PUT /items/456 |
Delete an item | POST /removeItem?itemId=456 | DELETE /items/456 |
比较 RPC 和 REST 的请求样式
我选择了一些项目来比较 RPC 和 REST 的请求样式:
- 漂亮
- 可设计性
- API定义语言
- 可预测性和语义
- 超媒体性
- 可缓存性
- 易用性
漂亮
即使这个项目无关紧要,因为美在旁观者的眼中,两种风格都可以产生漂亮的 API和丑陋的 API。
操作 | RPC | REST |
---|---|---|
Read a person pretty version | GET /readPerson?personid=1234 | GET /persons/1234 |
Read a person ugly version | GET /rdXbzv01?i=1234 | GET /xbzv01/1234 |
所以这是一个平局。
可设计性
设计 RPC 或 REST 端点是否更容易?
设计 RPC API 似乎更容易:
当您必须处理现有系统时,由于它通常是面向操作的,但您使用REST时必须简化和清理这个操作以暴露它。
- 当您主要处理流程和操作时(因为它们并不能很轻松的转换为 REST)。
- RPC API让设计人员实现一致的API更为困难,因为您没有真正的约束。
当您主要处理数据时,设计 REST API 似乎更容易。
但即使在某些情况下,设计 REST API 似乎比 RPC 更难一些,但它为您提供了一个框架,让您可以更轻松地实现一致的 API。
在这两种情况下,您都必须处理命名一致性问题。
两种风格各有优缺点,具体取决于上下文,但我不认为一种风格比另一种更容易设计。由于我没有真正看到赢家,这是另一场平局。
API 定义语言
您可以使用 Swagger、RAML 或blueprint等 API 定义语言完美地描述这两种风格。
可预测性和语义
对于 RPC,语义(主要)依赖于资源(endpoint),并且对其含义没有全局共享的理解。例如,要删除一个项目,您可以:
- GET(或 POST)/deleteItem?itemId=456
- GET(或 POST)/removeIt?itemId=456
- GET (或 POST) /trash?itemId=456
要退出该服务,您可以:
- POST (或 GET) /resign
- POST (或 GET) /goodbye
- POST (或 GET) /seeya
使用 RPC,您依靠人类对资源(endpoint)含义的解释来理解它的作用,但因此您可以对调用此资源(endpoint)时发生的事情进行良好的人类可读描述。
使用 REST,语义(主要)依赖于 HTTP 动词。动词的语义是全局共享的。删除项目的唯一方法是:
- DELETE /items/456
如果用户想停止使用您的服务,您将执行此(不那么明显)调用:
- DELETE /users/1234
REST 比 RPC 更具可预测性,因为它依赖于 HTTP 动词的共享语义。你不知道到底发生了什么,但你对你所做的事情有一个大致的了解。
REST 获胜
超媒体性
在这两种风格中,您都会结束发出 HTTP 请求,因此使用这些风格中的任何一种设计超媒体 API 都没有问题。
这是平局
可缓存性
我经常看到 (http) 缓存被用作选择 REST 而不是 RPC 的杀手级理由。
但是在阅读了 HTTP RFC 之后,我不同意这个论点(也许我错过了一些东西)。当然,如果您的 RPC API 仅对所有请求使用 POST,则缓存处理起来可能有点棘手(但并非不可能)。如果您明智地使用 GET 和 POST,您的 RPC API 将能够获得与 REST API 相同级别的缓存能力。
这是平局。
易用性
从开发人员的角度来看,两种风格都使用 HTTP 协议,因此 RPC 和 REST 请求之间基本上没有区别。文档(人类可读的机器)级别也没有区别。
这是平局。
总分
项目 | 谁赢 |
---|---|
漂亮性 | 平局 |
可设计性 | 平局 |
API定义语言 | 平局 |
可预测性和语义 | REST |
超媒体性 | 平局 |
可缓存性 | 平局 |
可用性 | 平局 |
REST 真的会赢吗?
由于可预测性和语义,REST获胜。 那么,资源方法是否比操作方法更好?
不。
RPC 和 REST 只是各有优缺点的不同方法,两者都具有价值,具体取决于上下文。您甚至可以在一个 API 中混合使用这两种方法。
关键在于上下文。没有万能的解决方案,不要盲目跟风,你总是要在一个上下文中思考,在选择解决方案时必须务实。
至少,我现在知道为什么我喜欢资源方法:它的可预测性和充分利用 HTTP 协议给出的框架。那你呢?
最后一句话让你深思:在这个函数式编程出现的时代,拥有操作请求风格是有意义的……