学习笔记-架构的演进之如何做到RESTful-2月day11

Richardson 成熟度模型

伦纳德 · 理查德森(Leonard Richardson)提出过一个Richardson Maturity Model,RMM即Richardson成熟度模型,用来衡量“服务有多么 REST”。
RMM从低到高分为 0 至 3 共 4 级:

  1. The Swamp of Plain Old XML:完全不 REST
  2. Resources:开始引入资源的概念。
  3. HTTP Verbs:引入统一接口,映射到 HTTP 协议的方法上。
  4. Hypermedia Controls:超文本驱动,或者是Fielding论文里的说法Hypertext as the Engine of Application State(HATEOAS)
    在这里插入图片描述

REST 的不足与争议

1 面向资源的编程思想只适合做 CRUD,只有面向过程、面向对象编程才能处理真正复杂的业务逻辑。

这个争议产生的原因是REST所依赖的HTTP协议的 4 个最基础的命令 POST、GET、PUT 和 DELETE,直接对应了CRUD 操作。
但REST涵盖的范围当然远不止于此。我们必须泛化地去理解这个CRUD:它们涵盖了信息在客户端与服务端之间流动的几种主要方式(比如 POST、GET、PUT 等标准方法),所有基于网络的操作逻辑,都可以通过解决“信息在服务端与客户端之间如何流动”这个问题来理解,有的场景里比较直观,而另一些场景中可能比较抽象。针对那些比较抽象的场景,如果确实不好把 HTTP 方法映射为资源的所需操作,REST 也并不会刻板地要求一定要做映射。这时,用户可以使用自定义方法,按 Google 推荐的 REST API 风格来拓展 HTTP 标准方法。
自定义方法应该放在资源路径末尾,嵌入冒号加自定义动词的后缀。比如与DELETE相对应的恢复操作undelete,可以通过自定义参数实现:

POST /user/user_id/cart/book_id:undelete

删除/恢复的完整设计是:设计一个回收站的资源,在那里保留还能被恢复的商品,我们把恢复删除看作是对这个资源的某个状态值的修改,映射到 PUT 或者 PATCH 方法上。

这里关键的问题是,不同架构设计上的差异,主要是因为对问题的抽象角度不同

  • 面向过程编程,以算法和处理过程(行为)为中心,是为了符合计算机bit世界中主流的交互方式。
  • 面向对象编程,将数据和行为统一起来、封装成对象,是为了符合现实世界的主流交互方式。
  • 面向资源编程,将数据(资源)作为抽象的主体,把行为看作是统一的接口,是为了符合网络世界的主流的交互方式。

2 REST 与 HTTP 完全绑定,不适用于要求高性能传输的场景中

面向资源编程与协议无关,但是 REST(特指 Fielding 论文中所定义的 REST,而不是泛指面向资源的思想)的确依赖着 HTTP 协议的标准方法、状态码和协议头等各个方面。
HTTP 是应用层协议,而不是传输层协议,如果我们只是把 HTTP 用作传输是不恰当的。因此,对于需要直接控制传输(如二进制细节 / 编码形式 / 报文格式 / 连接方式等)细节的场景,REST 确实不合适。这些场景往往存在于服务集群的内部节点之间。

3 REST 不利于事务支持

这个问题取决于我们对“事务(Transaction)”的理解:

  1. 如果“事务”指的是数据库那种狭义的刚性 ACID 事务,那分布式系统本身跟它之间就是有矛盾的(CAP 不可兼得)。这是分布式的问题,而不是 REST 的问题。
  2. 如果“事务”是指通过服务协议或架构,在分布式服务中,获得对多个数据同时提交的统一协调能力(2PC/3PC),比如WS-AtomicTransaction和WS-Coordination这样的功能性协议,那 REST 确实不支持。假如你已经理解了这样做的代价,仍决定要这样做的话,Web Service 是比较好的选择。
  3. 如果“事务”是指希望保证数据的最终一致性,说明你已经放弃刚性事务了。这才是分布式系统中的主流,使用 REST 肯定不会有什么阻碍,(当然,对于最终一致性的问题,REST 本身并没有提供什么帮助,而是完全取决于你系统的事务设计。)。

4 REST没有传输可靠性支持

REST并没有提供对传输可靠性的支持。因为在 HTTP 中,你发送出去一个请求,通常会收到一个与之相对的响应,比如 HTTP/1.1 200 OK 或者 HTTP/1.1 404 Not Found 等。但是,如果你没有收到任何响应,那就无法确定消息到底是没有发送出去,还是没有从服务端返回回来。这其中的关键差别,是服务端到底是否被触发了某些处理?
应对传输可靠性最简单粗暴的做法,就是把消息再重发一遍。这种简单处理能够成立的前提,是服务具有幂等性(Idempotency),也就是说服务被重复执行多次的效果与执行一次是相等的。
HTTP 协议要求 GET、PUT 和 DELETE 操作应该具有幂等性,我们把 REST 服务映射到这些方法时,也应该保证幂等性。

5 REST缺乏对资源进行“部分”和“批量”的处理能力

这个问题可能是接下来面向资源设计风格的API要解决的问题。
REST开创了面向资源的服务风格,却肯定不完美。以 HTTP 协议为基础,虽然给 REST 带来了极大的便捷(不需要额外协议,不需要重复解决一堆基础网络问题,等等),但也成了束缚 REST 的无形牢笼。(这也很像JS,本身的设计有很多缺陷,因为大家用的很多,反而越来越流行)

  1. 缺少对资源的“部分”操作的支持
    有些时候,我们只是想获得某个资源的某个属性,但常规REST操作是以资源为基本操作单元的。这个问题的根源在于,HTTP 协议对请求资源完全没有结构化的描述能力,所以返回资源的哪些内容、以什么数据类型返回等等,都不可能得到协议层面的支持。如果要实现这种能力,你就只能自己在 GET 方法的 Endpoint 上设计各种参数。

  2. 缺少对资源的“批量”操作的支持
    因为,对于HTTP 协议来说,它的无状态性不适用于(并非不能够)处理这类业务场景。有时候,我们不得不为此而专门设计一些抽象的资源才能应对。

总结

在软件行业发展的初期,程序编写都是以算法为核心的,程序员会把数据和过程分别作为独立的部分来考虑,数据代表问题空间中的客体,程序代码则用于处理这些数据。这种直接站在计算机的角度去抽象问题和解决问题的思维方式,就是面向过程的编程思想。与此类似,后来出现的面向对象的编程思想,则是站在现实世界的角度去抽象和解决问题。它把数据和行为都看作是对象的一部分,以方便程序员用符合现实世界的思维方式,来编写和组织程序。我们今天再去看这两种编程思想,无论用哪种思维来抽象问题都是合乎逻辑的。如今,站在网络角度考虑如何对内封装逻辑、对外重用服务的新思想,也就是面向资源的编程思想,又成为了新的受追捧的对象。面向资源编程这种思想,是把问题空间中的数据对象作为抽象的主体,把解决问题时从输入数据到输出结果的处理过程,看作是一个(组)数据资源的状态不断发生变换而导致的结果。这符合目前网络主流的交互方式,也因此 REST 常常被看作是为基于网络的分布式系统量身定做的交互方式。

此文章为2月Day10学习笔记,内容来源于极客时间《周志明的软件架构课

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值