Retrofit解析1之前哨站——理解RESTful

从今天开始,我开始学习Retrofit,整体Retrofit内容如下:

好的,那开始今天的内容

随着Google对HttpClient的摒弃,和Volley的逐渐没落,OkHttp开始异军突起,Retrofit对OkHttp进行了强制依赖。Retrofit是由Square公司出品的针对于Android和Java的类型安全的Http客户端,如果看源码会发现其实本质上是OkHttp的封装,使用面向接口的方式进行网络请求,利用动态生成的代理类封装了网络接口请求的底层,其将请求返回JavaBean,对网络认证REST API进行了很友好的支持。使用Retrofit将会极大的提高我们应用的网络体验。

本篇文章是Retrofit的前哨站——理解RESTful。因为retrofit是基于RESTful架构。所以在讲解Retrofit之前,先来复习一下RESTful。本篇文章内容如下:

  • 1.RESTful的前世今生
  • 2.RESTful的理解
  • 3.RESTful的原则
  • 4.RESTful、RPC、SOAP的爱恨情仇
  • 5.总结

在移动互联网的大潮下,前后端分离的场景下,随着docker等技术的兴起,“微服务”的概念越来越被大家接受的的情况下,RESTful API成为越来越重要的移动端和服务器的交互形式。尤其在很多互联公司或者传统公司转型拥抱互联网的公司,一套设计良好的RESTful API能够帮助互联网产品支持单个服务端+多个客户端的场景。RESTful架构本身是一个风格而不是一个标准,本文将围绕RESTful架构展开讨论,欢迎大家拍砖。

RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、方便扩展,所以得到越来越多的应用。
但是,RESTful到底是什么?并不是一个容易说清楚的问题。那么我们先来了解下RESTful的前世今生。

一、RESTful的前世今生

、RESTful之父---Roy Fielding

在介绍RESTful之前需要介绍一下Roy Fielding。RESTful这个单词因为是在2000年的他的博士论文中首次出现的。
Roy Fielding是一个非常重要的人,他是HTTP协议(1.0/1.1)的主要设计者、Apache服务器软件的作者之一,Apache基金会的第一任主席。所以他的这篇论文已经发布,就引起了关注,并且立即对互联网产生了深远的影响。

Roy Fielding.png

他这样介绍论文的写作目的:

"本文研究计算机科学两大前沿----软件和网络----的交叉点。长期以来,软件研究主要关注软件设计的分类、设计方法的演化,很少客观地评估不同的设计选择对系统行为的影响。而相反地,网络研究主要关注系统之间通信行为的细节、如何改进特定通信机制的表现,常常忽视了一个事实,那就是改变应用程序的互动风格比改变互动协议,对整体表现有更大的影响。我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。"
(This dissertation explores a junction on the frontiers of two research disciplines in computer science: software and networking. Software research has long been concerned with the categorization of software designs and the development of design methodologies, but has rarely been able to objectively evaluate the impact of various design choices on system behavior. Networking research, in contrast, is focused on the details of generic communication behavior between systems and improving the performance of particular communication techniques, often ignoring the fact that changing the interaction style of an application can have more impact on performance than the communication protocols used for that interaction. My work is motivated by the desire to understand and evaluate the architectural design of network-based application software through principled use of architectural constraints, thereby obtaining the functional, performance, and social properties desired of an architecture. )

二、REST的理解

(1)、Roy Fielding将他对互联网软件的架构原则,定名为REST,即Representation State Transger的缩写。所以REST指的是一组架构约束条件与原则。"如果一个架构符合REST的约束和原则",我们就称它为RESTful架构。
(2)、Representation State Transger有人翻译为表征状态转移,也有人翻译为表述性状态转移,也有人翻译为表现层状态转移,也有人翻译为"呈现状态转移"。我的理解是"表征状态转移"。
(3)、REST本身并没有创建新的技术、组件或服务,而隐藏在RESTful背后的理念就是使用Web的现有特征和能力,更好地使用现有Web标准中的一些准则和约束。虽然REST本身收Web技术的影响很深,但是理论上REST架构风格并不是绑定在HTTP上,只不过目前HTTP的唯一与REST相关的实例。所以我们这里描述的REST也是通过HTTP实现的REST。

三、相关概念的梳理:

  • REST(Respresentational State Transfer):定义了一套基于Web的数据交互方式的设计风格
  • RESTful:符合REST风格的API就可以叫做RESTful API。注意,本文讲到的RESTful API设计方法将是基于HTTP和JSON实现方式,但不论HTTP还是JSON都不是REST的标准。REST只是风格,没有标准。
  • RPC(动词) :REST强调资源,RPC强调动作,所以REST里面的URI是名词,RPC多为动词短语,然而它们也并不是完全不想管的两个东西。
  • WebService:一个貌似很久远的概念,有一套它的理论,基于Web的服务提供者

四、REST关键原则

由于REST定义了应该如何正确的使用Web标准,例如HTTP和URI。如果你在设计应用程序的时能坚持REST原则,那就预示着你将会得到了一个优质的Web架构。REST有5条关键原则如下:

  • 1.为所有“事物”定义ID
  • 2.将所有事物链接在一起
  • 3.使用标准方法
  • 4.资源多重表述
  • 5无状态通信

下面让我们来详细解析一下:

1、为所有"事物"

这里我使用了"事物"来代替更准确的术语"资源"。大家可以想一下人们构建的系统,通常会找到一系列的值来标识关键的抽象,就像数据库中的"表"里面的"主键"一样,那么在web的世界里面是什么那?大家答对了,就是URI,RUI构成了一个全局命名的空间。使用URI来标识你的关键资源意味着它们获得了一个全局的、唯一的ID。

记得之前看过一本书叫<Dont make me think>,里面阐述了一种思想,就是尽量使用那些能够被绝大多数人所能理解的规则,这样你做的任何东西对别人来说是没有学习成本的。同样的道理,如果在你的application里面定义一个对默写事务的抽象,别人能瞬间理解(比如消费者,应该定义为consumer)。更加直观的讲,在淘宝上每一个商品都有他的一个固定的ID(URI)。否则,那就扎心了,老铁。

当这样设计的时候,很多人会怀疑这样是否会直接向外面暴露你的数据库记录。但是其实它和隐藏现实细节之间没有任何冲突,通常值得被URI标识的事物——资源——要比数据库记录要抽象的多。例如,一个订单资源可以由订单项,地址以及其他方面组成。标识所有值的标识事物,领会这一个观念可以引导你创建出在传统应用程序中不常见的资源。一个流程,一个谈判,一次饭局,这都是应该标识的事务的示例。

下面是一些你可能想到的URI的例子:

http://example.com/customers/1234
http://example.com/orders/2007/10/776654
http://example.com/products/4554
http://example.com/processes/salary-increase-234

基于我创建了便于阅读的URI——这个有用的观点,尽管不是RESTful设计所必须的,但是你们应该会十分容易的推测出 URI的含义:他们明显的"标识"某一数据的数据项。
继续往下看

http://example.com/orders/2007/11
http://example.com/products?color=green
大家看到这两个URI看起来和之前有些不同,因为它们不是对一件事物的标识,而是对一类事物的标识(假设第一个URI标识了所有2007年11月份的订单,第二个标识了绿色产品的集合)。但是这些集合自己也是事物(资源),也应该被标识。

PS:使用全局、唯一的命名规则的好处,既适用于浏览器中的Web应用,也适用于当前的移动互联网中的app应用。

最后总结一下:使用URI标识所有值得标识的事务,特别是应用中提供的所有"高级"资源,无论这些资源代表单一数据、数据项集合、虚拟亦或实际的对象还是计算结果等。

2、将所有事务连接在一起

这里说的是“链接”的思想,链接在我们HTTP中是非常常见的概念。但是他的用处应该不止于此,比如下面的json

{"url":"https://www.hao123.com/"}

但你看见上面的链接,应用程序可以通过检索json,跟踪链接获取更多的信息。使用URI表示链接的优雅之处在于,链接可以指向不同应用、不同服务器甚至位于南极洲的服务器。因为URI命名规范是全球标准,构成WEB的所有资源都可以互联互通。

链接的原则还有一个更重要的方面——应用"状态"。简而言之,实际上服务器端为客户端提供一组链接,使客户端能通过连接将应用从一个状态改变为另一个状态。稍后我们会在另一篇文章探究这个方面的影响;目前,只需要记住链接是构成动态应用的有效方式。

总结一下:任何可能的情况下,使用链接指引可以被标示的资源。也正是链接造就了现在的Web。

3、使用标准方法

当你在浏览器里面输入一个uri的时候,浏览器就会跳转你制定的地址。但是你的浏览器是怎么知道该如何操作的那?那是因为浏览器知道所有的资源(uri)都支持同样的接口。一套同样的方法,如下图所示


方法.png

其中HEAD,TRACE,OPTIONS,CONNECT 在RESTful API 设计中不常用,这些Methods具体定义可以在

其中 HEAD,TRACE,OPTIONS,CONNECT 在 RESTful API 设计中不常用,这些 Methods 具体定义可以在这里找到。如果需要,可以根据相关语意来实现具有对应功能的API。

如果你采用RESTful的方式暴露应用功能,那这条原则和它同样也适用于你。

为什么使用标准方法如此重要?从根本上说,它使你的应用称为Web的一部分——应用程序为Web变成Internet上最成功的应用所做的贡献,与它添加到Web中的资源数量成比例。采用RESTful方式,一个应用可能会向Web中添加数以百万计的客户uri。

统一接口也使用所有理解HTTP应用协议的组件能与你的应用交互。通用客户程序就(generic client)是从从收益的例子,比代理,缓存,网关等。

总结一下:为了使客户端程序能与你的资源相互协作,资源应该正确地实现默认的HTTP协议(HTTP),也就是使用标准的GET/PUT/POST/DELETE方法。

4、资源多重表述

到目前为止我们忽略了一个复杂的问题:客户端程序如何知道怎么处理检索的导数据,比如GET或者POST请求的结果?其实HTTP采取的方式是允许数据处理和操作调用之间的关系分离的。换句话说,如果客户程序知道如何处理一种特定的数据格式,那就可以与所有提供这种格式的资源交互。让我们再用一个例子来阐述这个观点,利用HTTP内容协商(content negotiation),客户端程序可以请求一种特定格式的表述:

GET /customers/1234 HTTP/1.1
Host: example.com 
Accept: application/vnd.mycompany.customer+xml  

响应的返回值可能是一些公司专有的XML格式表述的客户信息。
假设客户端发起的请求是另外一个不同的请求,如下:

GET /customers/1234 HTTP/1.1
Host: example.com 
Accept: text/json

响应的返回值就可能是json格式的
这说明为什么理想的情况下,资源表述应该采用标准格式,如果客户端对HTTP应用协议和数据格式都有所"了解"。那么它就可以用一种有意义的方式与世界上任意一个RESTful HTTP应用交互。
在实际应用中,资源多重表述还有其他的好处:如果你为你的资源提供HTML和XML两种表述方式,那这些资源不仅可以被你的应用所用,还可以被任意标准Web浏览器所用。你的应用信息可以被所有会使用Web的人获取到。
总结:针对不同的需求提供资源多重表述。

五、无状态通信

所谓无状态通信,即所有的资源,都可以通过URI定位,而且这个定位与其他资源无关,也不会因为其他资源的变化而改变。有状态和无状态的区别,举个例子说明下。例如查询某员工的工资,以为查询工资是需要登录系统,进入查询工资的页面,执行相关操作后,获取工资的信息,则这种情况吸是有状态的,因为查询征信的每一步操作都依赖于前一步的操作,只要前置操作不成功,后续操作就无法执行;如果输入一个URI即可得到指定某人的工资,则这种情况是无状态的,因为获取工资的信息是不依赖其他资源或者状态,且这种情况下,某人的工资信息是一个资源,由一个URI与之相对应,可以通过HTTP中的GET方法获取资源,这就是典型的RESTful风格。

有状态.png
无状态.png

五、ROS、SOA、REST与RPC

ROA即Resource Oriented Architecture,RESTful架构风格的服务是围绕资源展开的,是典型的ROA架构,虽然ROA与SOA并不冲突,甚至把ROA看做SOA的一种未尝不可。因此RESful架构风格的服务通常被称之为ROA架构,很少提及SOA架构,以便更加显示的与RPC区分。

PRC风格曾是WebService的主流,最初是基于XML-PRC协议,后来渐渐被SOAP协议取代;但是RPC的风格不仅仅可以用HTTP,还可以用TCP或者其他通信协议。但是PRC风格的服务,受服务器采用语言的束缚比较大。进入移动互联网时代后,RPC风格的服务很难在移动端使用,而RESTful风格的服务,由于可以直接以json为载体承载数据,以HTTP方法为统一接口完成数据操作,客户端的开发部依赖于服务实现的技术,移动端也可以轻松使用服务,这也加剧了REST取代RPC称为Web Service的主导

RPC与RESTful的区别如下面两个图所示

RPC.png
RESTful.png

六、总结

最后我们从REST的名字来重新分析并总结一下REST。
REST的全拼是(Respresentational State Transfer) 其中Respresentational指的是资源即Resource 而State Transfer 是状态转化,那么我从这两个方面来重新解读一下

1、资源(Resources)是REST的核心

REST开发又被称作“面向资源的开发”,这说明对于资源的抽象是设计RESTful API的核心内容。RESTful API建模的过程与面向对象建模类似,是以名词为核心的。这些名词就是资源,任何可命名的抽象概念都可以定义为一个资源。对于业务的抽象是设计一套好的RESTful API的基础,这就好比建房子打地基,如果地基没有打好,后面建的楼就很容易歪掉,其美观度,可维护性,可扩展性就会大大折扣。我会建议在设计初期一定要在资源的定义上多花功夫,抽象出适合业务发展的资源。也就是说一开始要把产品的RESTful风格定义下来,后面的扩展都可以基于这样的风格延续下去。

下面是几条小的建议:

  • 理清资源的层次结构,比如业务针对的范围是养鸡场,那么学校会是一级资源(/school),老师(/school/teachers),学生(school/students)就是二级资源。
  • 资源尽量用准备的英文名词去表达,资源组都是用复数来表示。一个号的资源定义一定是不需要解释的。
2、资源的状态转化(State Transfer)

访问一个网站或者接口,就代表客户端和服务器一次交互的过程,而这个过程势必会涉及到数据和状态的变化。而HTTP协议又是无状态的,这就意味着所有的状态都保存在服务器。如果某个客户端想要做操作服务器必须通过某种手段让服务器发生状态转换,那么客户端就可以操作资源,而资源的状态转化就转化为对资源的各种操纵。而这些操作通常是通过HTTP协议的四种方法来实现的GET/POST/PUT/DELETE。还有其他不常用的方法PATCH/HEAD/OPTIONS。

最后再次重申RESTful 是风格,不是标准。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 67,920评论 12 114
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 122,770评论 15 534
  • 一说到REST,我想大家的第一反应就是“啊,就是那种前后台通信方式。”但是在要求详细讲述它所提出的各个约束,以及如...
    时待吾阅读 1,173评论 0 14
  • REST本身是一个高度抽象化的架构风格,因而总是很难对它有一个比较深入且印象深刻的理解。写这篇文章的目的,是自己对...
    vito1994阅读 830评论 0 24
  • 五十双期盼的目光,紧紧的盯着你,你婉然一笑,捉不到紧张的影子,你的一言一语、一个音调、一声轻笑,都深深刻在我心间,...
    欧飞云阅读 54评论 0 0