前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你真的知道你喜欢REST而不是RPC的原因吗?

你真的知道你喜欢REST而不是RPC的原因吗?

作者头像
ImportSource
发布2018-04-03 14:15:58
1.1K0
发布2018-04-03 14:15:58
举报
文章被收录于专栏:ImportSourceImportSource

本文讨论的内容主要是请求风格,所以本文中所说RPC侧重于HTTP请求风格,而非java中的RPC设计模式。

有关REST和RPC的讨论或争论一直活跃在各个技术角落,最近也关注了不少,看了很多人的看法之后,我意识到这个问题可以帮助我照亮自己的知识死角:为什么我喜欢REST的请求风格(资源导向)比RPC(操作导向)多一点呢? 是因为RPC的请求风格天生邪恶吗? 还是REST就是灵丹妙药?

两种请求风格长分别长什么样子

在比较这两种请求风格之前,让我们看看他们究竟长什么样子。

HTTP 请求

RPC和REST都是使用HTTP协议(如果你对rpc有其他认识,你可以忽略这句话)。http协议就是一个request/response协议。

一个基本的HTTP请求包含如下:

  • 一个动词(或叫方法)
  • 一个资源 (或叫endpoint)

每个HTTP动词又有如下特点:

  • 表示一个意思。
  • 不一定是幂等的。至于幂等是什么鬼?一般情况下如果向服务器发送该方法的多个相同请求的预期效果与对单个这样的请求的效果相同,则请求方法被认为是“幂等的”。
  • 不一定是安全的。有可能是安全的,也有可能是不安全的: 如果request方法的定义语义本质上是只读的,那么就被认为是“安全的”。
  • 可以被缓存或者不可以,cacheable or not。

上面这个表格中只是展示了RPC和REST API中常用的几个HTTP动词

RPC: 一个基于操作的请求风格

RPC首字母缩略词有很多含义,远程过程调用(Remote Procedure Call)也有很多的形式。

在这篇文章中,当我谈论RPC我们一般都指的是:你的GET或POST方法是一个什么操作。

使用这种类型的RPC,您可以通过HTTP作为传输协议来操作数据。

就我目前所知,对于这种风格基本上没什么明确的约定和规则

  • 端点(或叫资源)包含要调用的操作的名称。
  • 这种风格的API基本上只使用两个http动词,那就是你熟悉的GET和POST。
代码语言:javascript
复制
GET /someoperation?data=anId

POST /anotheroperation
{
  "data":"anId"; 
  "anotherdata":"another value"
}

那么人们是怎么选择GET还是POST呢?

  • 对于那些比较关心HTTP协议的人来说,这种类型的API往往使用GET来进行不修改任何内容的操作,而POST则用于其他情况。
  • 对于那些不太在意HTTP协议的人来说,这种类型的API往往使用GET来执行不需要太多参数的操作,而POST则用于其他情况。
  • 那些彻底不关心http动词或压根不知道的人来说,就会在GET和POST之间随机选择或总是使用POST。这种情况也是大多数情况,至少在国内来说。

REST: 一种基于资源(resource)的请求风格

我不会详细解释到底什么是REST,你可以阅读Roy Fielding的论文和REST cookbook的更多细节。

为了聚焦本文的主题,我们长话短说:使用REST API,你是将数据作为资源(resource),你通过HTTP协议使用正确的HTTP动词操作,注意,是正确的动词:

  • 端点上包含你要操作的资源。
  • 许多人喜欢使用CRUD类比来解释REST请求原则。 HTTP动词表示你要怎么操作这个资源(创建/读取/更新/删除)。
代码语言:javascript
复制
GET /someresources/anId

PUT /someresources/anId
{"anotherdata":"another value"}

上例子

下面是分别用RPC和REST两种方式来编写的API:

RPC和REST大决战

既然大家都在一个劲的争论到底谁好,或者REST就是好,RPC就是不好,等等。为了能把问题说清楚,我们试图寻找一些比较指标,然后对二者进行一个全方位的对比,看最后是谁胜出?

下面是我们列举的一些指标,来比较这两种风格:

  • 颜值
  • 设计性
  • API 定义语言
  • 可预测性和语义
  • 超媒体性
  • 可缓存性
  • 可用性

颜值

看起来两种风格都可以设计出丑的API,也都可以设计出美的API。平手。

设计性

设计RPC API看起来更容易:

当你处理一个现有的系统时,因为它通常面向操作,所以基于RPC的API与之天然匹配。但RPC API的设计需要设计人员严格的实现一致性API,因为实际上它没有什么约束。完全依赖于设计人员的一致性执行能力。

如果你主要是处理数据,REST API可能更容易一些。

但某些情况下,设计一个REST API似乎比RPC更难一点,因为它给你定了一个框框,让你实现一致的API,让你必需依赖于资源,而不是操作。

这两个都需要去处理命名的一致性。

这两种风格都依赖于具体项目的具体情况,所以真的没法分辨哪个设计起来更容易一些。

所以,平手。

API 定义语言

你可以使用例如Swagger, RAML or blueprint等这些api 定义语言来很好地描述这两种风格。

平手。

可预测性和语义

使用RPC,语义大部分时候是依赖在端点上的,并且没有对其含义的全局共享理解,什么意思呢?就是没有一个规范和约定。 例如,删除一个项目:

  • GET (or POST) /deleteItem?itemId=456
  • GET (or POST) /removeIt?itemId=456
  • GET (or POST) /trash?itemId=456

还有比如resign操作,你可以命名成下面任何一个似乎都没什么问题:

  • POST (or GET) /resign
  • POST (or GET) /goodbye
  • POST (or GET) /seeya

使用RPC,您依赖于人类对端点的含义的理解来理解它的作用,因此您可以对调用此端点时发生的事情进行精细的人工可读描述。

使用REST,语义依赖主要依赖于HTTP动词。 动词的语义是全局共享的,约定好的。 删除项目的唯一方法是:

  • DELETE /items/456

如果用户想注销,您可以这样做:

  • DELETE /users/1234

REST比RPC更可预测,因为它依赖于HTTP动词的共享语义。 你不知道具体发生了什么,但你大概知道自己要做什么。

本局 REST 胜出。

超媒体性

这两种风格都是使用的HTTP的请求,所以都可以设计出超媒体(hypermedia)的API。

平手。

可缓存性

我们经常可以在网上看到选择REST的一个致命的理由就是http 缓存。

但看了HTTP RFC后,我不同意这个论点(也许我理解的不够深刻)。 当然,如果你的RPC API所有请求都使用POST,缓存处理起来可能有点棘手。 如果你使用GET和POST的话,你的RPC API也将能够获得与REST API相同的缓存能力。

所以,这局平手!

可用性

从开发人员的角度来看,两种样式都使用HTTP协议,因此RPC和REST请求之间基本没有区别。

平手。

总比分

指标

胜出方

颜值

平手

设计性

平手

API 定义语言

平手

可预测性和语义

REST

超媒体性

平手

可缓存性

平手

可用性

平手

REST真的就赢了吗?

REST胜出要归结于“可预测性和语义”这一项指标。

那么,是不是就可以此断言基于资源比基于操作好吗?

No.

RPC和REST各有利弊,各有价值(我真的不想说出如此没有性格的话)。 你甚至可以在单个API中混合使用这两种方法。虽然我并不想得出这样的结论,但根据上面的分析确实是这样。

具体环境,这是关键。 没有灵丹妙药的解决方案,也没必要盲目去追随时尚,你总是必须在一个具体环境中去思考,用我们程序猿的话就是“上下文”, Context,在选择解决方案时必须务实。

至少,我现在知道为什么我喜欢基于资源的这种模式(REST)了:其可预测性以及充分利用HTTP协议特性。

你呢?

最后说一句:在如今这个功能编程还是主流的时代,基于操作的请求风格也是有其现实意义的,但在微服务时代(或者说在微服务场景下)呢?

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-01-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ImportSource 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档