RestFul风格的理解

平常经常听到RestFul相关的内容有时候说是RestFul架构、有时候说是RestFul风格,有时候还会拿它与RPC来做对比,那么他到底是什么呢?一直以来我也不是很明白说是说理解的是是而非,真正对RestFul有一个较为全面的理解是从读了周志明老师的《凤凰架构》开始的,关于这一本数有一个网页版的,感兴趣的同学可以前去学习。这是一本很好地书,里面也有很多其他方面的内容可供大家学习,这篇文章的内容都也脱胎与《凤凰架构》这本书

https://icyfenix.cn/architect-perspective/general-architecture/api-style/rest.html

1、RestFul是什么?

RestFul准确的来说是一种网络建构风格,他对架构的实现并没有强制的一些约束。REST是英文Representational State Transfer的首字母组合,因为我们将至翻译为“表征状态转移”。这是一个让人初步听起来很懵逼的词汇。现在用自己的话来描述就是提出这个概念的作者将我们在互联网中的信息称之为资源,那么资源肯定是有一种变现形式的,这种变现形式我们就将至称之为表征,就像我们浏览一个网页似的,我们看到的HTML页面就是就是表征里面的信息就是资源,当我们看完当前的界面点击进入下一个界面时,这时候页面发生了转变(信息发生了改变,也可能表现形式也发生了改变)这个改变我们就可以称之为状态转移。那么这个状态是如何转移的?是由什么驱动的?我们又该如何做到这些做到这些的过程中要遵循哪些原则或是说我们是想要通过遵循这个原则获取到什么样的好处,这就是RestFul要阐述的东西。说到这里我们实际上明白光说“表征状态转移”我们并不能理解,如果我们要是把他描述为“资源的表征状态转移”在结合上面的介绍我们就好理解了,接下来我们要梳理清楚的就是这里面的几个名词定义。

  • 资源(Resource):

    就像我们看一本书,书中的信息就是资源,这个资源虽然可以是HTML界面、纸质书籍、PDF但是他们的内容都是一样的

  • 表征(Representation):

    表征就是上面我们说的——HTML界面、纸质书籍、PDF…

  • 状态(State):

    上面我们提到的翻页就是一种状态的转换,那么翻页前是一个状态翻页后是一个状态。状态时间是怎样驱动呢,这就是下面我们要介绍到的统一接口

  • 统一接口(Uniform Interface):

    在上面的转态转移例子中我们是更新了页面的内容,按照我们平时的理解就是我们请求了新的内容。那么我们点击的是这个资源,在RestFul中我们也是面对资源进行操作的,他怎么指导我们是要对资源进行什么样的操作呢?如果我们在这个资源的定位中附加一个我们想要的动作信息是不是就可以了,正是如此,RestFul中引用了HTTP中的规定,有关动作的关键字有GET、HEAD、POST、PUT、DELETE、TRACE、OPTIONS 七种。分别表示不同的操作含义,不过上面我们也提到了一个面向资源的概念,有关这个概念可以类比于面向过程、面向对象的编程思想进行理解

  • 自描述信息(Self-Descriptive Messages)

    就是我们在请求头中添加的信息,eg:Content-Type : application/json; charset=utf-8。主要是用来告诉通信的双方如何处理接到的信息

  • 超文本驱动(Hypertext Driven)

    上面我们介绍到的状态转移是发生在服务端的(服务端提供了消息),但是这个也不是服务端想起来就自己来改变这个状态的而是我们通过页面中的一个连接,这个连接就是我们说的超文本。通过这个超文本我们可以通知服务端对那个资源进行操作通过上面的统一接口我们可以告诉服务端我们想要进行怎么样的操作。

    浏览器作为所有网站的通用的客户端,任何网站的导航(状态转移)行为都不可能是预置于浏览器代码之中,而是由服务器发出的请求响应信息(超文本)来驱动的。

2、RESTful系统

上面我们围绕REST对这个设计架构风格中的几个关键字做了解释,为了达到他的目的RESTful也提出了六大设计原则:

  • 服务端与客户端分离(Client-Server)

    前后端分离的概念在现在的系统中已经非常常见,他主要是为了提高系统的可移植性。但是前后端理念的普及最大的功劳并不能算在Restful的头上,主要的推动还是前端技术的逐步加强

  • 无状态(Stateless)

    上面我们提到状态在服务端发生了改变但是还有一个值得我们想的问题就是服务端怎么知道下一页是那一页?如果要是放在更完整的系统中就是我们要知道那个集团下的那个用户要那个信息。我们也可以将这个整个信息的定位理解为一个状态,状态是一定要有的问题在于保存到哪里——客户端、服务端。这里面我们说的无状态是相对于服务端而言的,如果做成了无状态那么可以一定程度上减轻服务端的负担,但是真是的项目中是不太可能实现的,真是的场景中可能往往伴随着大量的上下文,到现在最常见的方式就是服务端通过缓存或是一些其他的技术来实现一部分状态的持有。这里面可以联想系统中有关上下文的处理,就像会缓存一些用户的企业租户相关的信息

    在现在微服务的架构中,如果要是能做到服务端的无状态是可以很好获得很高的价值。

  • 可缓存(Cacheability)

    如果系统中的每一个请求都需要通过服务端请求得到,这样将会极大的拉胯系统的性能,最好的办法就是将系统请求的一部分数据缓存下来,从而提高系统的性能。个人理解RestFul是面向资源的编程理念,我们交互的单位可以看成是资源,我们缓存下来的东西也可以看成是资源,不过对于资源应该要知道这个资源是不是可以缓存,缓存的可以使用多长时间,这个需要服务端设计的时候考虑进来。

  • 分层系统(Layered System)

    这里说的分层并不是代码中说的controller、service、dao,主要指的是一个前后端之间的分层,是的前端的代码并不需要指导后端的具体地址,中间我们通过负载均衡或是网关的技术做一个处理,这样便于缓存、伸缩性扩展部署。这个最典型的应用场景就是CDN——内容分发网络

  • 统一接口

    在上面的我们也介绍过统一接口的概念,里面说的主要是RestFul风格借助HTTP1.0来规范了几种不同的行为,既然我们是面向资源编程又在接口中规定了动作,那么如何确定资源就是需要关系的,在RestFul风格中我们需要将资源进行编码,这样就可以定位到那个资源要做什么操作。

  • 按需代码(Code-On-Demand)

    按需代码的这条原则是建议实现,这倒也不是说这个原则的实现有多费劲而是考虑到实用性与经济行。向以前的Java Applet技术以及WebAssembly都是典型的按需代码,执行逻辑是放在服务端的,在需要的时候拿下来进行执行,执行完之后回在客户端销毁。客户端的JS应该也是这样的形式,在往大了的说现在所流行的说法就是手机上只保留很少的东西使用的时候app等信息都从服务端拉取。

3、RestFul的优点

  • 可以降低学习成本

    RestFul中我们规定了资源的统一接口,在资源中有通过相关的描述可以确定资源的位置或者说是什么资源。开发者可以通过这些信息就知道一个接口是用来对什么资源做什么操作的

  • 更加稳定可靠

    这个是因为他是背靠HTTP1.0,而HTTP已经经过多年的发展非常稳定,不过这个既是他的优点也是他的缺点

  • 具有天然的层次关系

    我们原来写的代码往往没有资源的概念更多的是以动词来描述节点的,但是在RestFul的指导中我们是以名词为中心点的,这就是得资源可以更有层次感,也可以用集合的概念去描述

4、RestFul的争议

  • 面向资源的编程思想只适合做CURD,面向过程与面向对象的编程思想才能处理真正复杂的业务逻辑

    自己也是赞成这样的思想的系统中应该融合多种技术或者是风格而非是剑走偏锋特别是对于大型的系统。

    1、面向过程编程时,为什么要以算法和处理过程为中心,输入数据,输出结果?当然是为了符合计算机世界中主流的交互方式。

    2、面向对象编程时,为什么要将数据和行为统一起来、封装成对象?当然是为了符合现实世界的主流的交互方式。

    3、面向资源编程时,为什么要将数据(资源)作为抽象的主体,把行为看作是统一的接口?当然是为了符合网络世界的主流的交互方式

  • Rest不能够适应高性能要求的场景

    这是因为RestFul是与HTTP绑定的而HTTP在网络分层中属于第七层,而我们现在常用的远程调用技术RPC是属于网络层的第四层,相对于RPC目前的REST性能更低。但是个人猜测既然RestFul作为一种编程风格有没有日后Rest与RPC相互借鉴融合的可能。

  • REST不利于事务支持

    这里说的事务不是刚性的ACID事务,对于分布式系统来书本来就存在CAP不可兼得理论,但是如果将事务理解成通过服务协议或是架构在分布式服务中获得对多个数据的协调统一能力,这时候就可以说REST不利于对事物的支持

  • 没有传输可靠性的支持

    这里说的主要是请求中幂等性的一个问题,在HTTP协议中是要求GET、PUT、DELETE具有幂等性,这里有些不太理解的是GET的幂等性,难道是害怕连续的多次请求得到的不是一个结果嘛❓

  • 缺乏对资源进行部分和批量处理的能力

    关于这一点是很好理解的,但是如果我们真的是采用了RestFul设计风格的网络架构,如果我们想要达到对数据部分或是批量的一个处理能力就需要对一些资源进行抽象分装,如果是这样的话感觉就有点与我们的初衷背道而驰了,可以说一定程度上是加大了我们的工作量。

5、RestFul的成熟度

RestFul的成熟度我们可以简要的分为三级,当然如果连资源的概念都没有那肯定就是零了,如果要是系统中有资源的概念例如以这样的形式返回数据:

[
	{id: 1234, start:"14:00", end: "14:50", doctor: "mjones"},
	{id: 5678, start:"16:00", end: "16:50", doctor: "mjones"}
]

这里我们的数据是有id编号的概念,我们也是可以定位资源的,这时候我们可以建资源的概念称之为一级。如果我们要是完善了统一接口可以通过Request中的method来指定对资源的不同操作形式我们就可以将系统称之为2级别,这时候是引入了统一接口的概念,回到文章开头提的也就是说我们的系统可以完成状态的转移。

虽然说RestFul的接口具有很强的可读性但是我们还是很难直接指导对一个固定资源进行固定操作应该调用什么样的接口,那么除了第一个请求是需要我们在浏览器中输入地址进行驱动外,其他所有的请求都能够根据返回的信息描述来指导后续要发生的状态转移,例如我们在第一次的请求中返回如下信息:

{
	schedules:[
		{
			id: 1234, start:"14:00", end: "14:50", doctor: "mjones",
			links: [
				{rel: "comfirm schedule", href: "/schedules/1234"}
			]
		},
		{
			id: 5678, start:"16:00", end: "16:50", doctor: "mjones",
			links: [
				{rel: "comfirm schedule", href: "/schedules/5678"}
			]
		}
	],
	links: [
		{rel: "doctor info", href: "/doctors/mjones/info"}
	]
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值