前端学习【RESTful架构篇】

前记:一开始原本是想用自己的语言写一篇关于RESTful架构的文章,然而无奈于自己也是刚刚接触,怕理解不到位有误导读者之嫌,故重新将这篇文章定位为了本人的RESRful学习路径。若有错误,还请大家指正。

什么是RESTful架构?


参考文献:理解 RESTful 架构 - 阮一峰

注:以下内容都引用自该文献

REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的。Fielding是一个非常重要的人,他是HTTP协议(1.0版和1.1版)的主要设计者、Apache服务器软件的作者之一、Apache基金会的第一任主席。所以,他的这篇论文一经发表,就引起了关注,并且立即对互联网开发产生了深远的影响。

Fielding将他对互联网软件的架构原则,定名为REST,即Representational State Transfer的缩写。我对这个词组的翻译是"表现层状态转化"

如果一个架构符合REST原则,就称它为RESTful架构。

要理解RESTful架构,最好的方法就是去理解Representational State Transfer这个词组到底是什么意思,它的每一个词代表了什么涵义。如果你把这个名称搞懂了,也就不难体会REST是一种什么样的设计。

REST的名称"表现层状态转化"中,省略了主语。"表现层"其实指的是"资源"(Resources)的"表现层"。

所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。你可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。

"资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的"表现层"(Representation)

比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现。

访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。

互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State Transfer)。而这种转化是建立在表现层之上的,所以就是"表现层状态转化"。

客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。

优秀的RESTful架构需要具备哪些特质?


参考文献:Principles of good RESTful API Design - (译:好 RESTful API 的设计原则 - moonz-wu)

注:以下内容都引用自该文献

这里有一些非常重要的术语,我将在本文里面一直用到它们:

资源:一个对象的单独实例,如一只动物
集合:一群同种对象,如动物
HTTP:跨网络的通信协议
客户端:可以创建HTTP请求的客户端应用程序
第三方开发者:这个开发者不属于你的项目但是有想使用你的数据
服务器:一个HTTP服务器或者应用程序,客户端可以跨网络访问它
端点:这个API在服务器上的URL用于表达一个资源或者一个集合
幂等:无边际效应,多次操作得到相同的结果
URL段:在URL里面已斜杠分隔的内容

一、四个半非常重要的HTTP动词

这里至少有四个半非常重要的HTTP动词需要你知道。我之所以说“半个”的意思是PATCH这个动词非常类似于PUT,并且它们俩也常常被开发者绑定到同一个API上。

GET (选择):从服务器上获取一个具体的资源或者一个资源列表。
POST (创建): 在服务器上创建一个新的资源。
PUT (更新):以整体的方式更新服务器上的一个资源。
PATCH (更新):只更新服务器上一个资源的一个属性。
DELETE (删除):删除服务器上的一个资源。
还有两个不常用的HTTP动词:

HEAD : 获取一个资源的元数据,如数据的哈希值或最后的更新时间。
OPTIONS:获取客户端能对资源做什么操作的信息。

一个好的RESTful API只允许第三方调用者使用这四个半HTTP动词进行数据交互,并且在URL段里面不出现任何其他的动词

二、版本信息

无论你正在构建什么,无论你在入手前做了多少计划,你核心的应用总会发生变化,数据关系也会变化,资源上的属性也会被增加或删除。只要你的项目还活着,并且有大量的用户在用,这种情况总是会发生。

请谨记一点,API是服务器与客户端之间的一个公共契约。如果你对服务器上的API做了一个更改,并且这些更改无法向后兼容,那么你就打破了这个契约,客户端又会要求你重新支持它。为了避免这样的事情,你既要确保应用程序逐步的演变,又要让客户端满意。那么你必须在引入新版本API的同时保持旧版本API仍然可用。

注:如果你只是简单的增加一个新的特性到API上,如资源上的一个新属性或者增加一个新的端点,你不需要增加API的版本。因为这些并不会造成向后兼容性的问题,你只需要修改文档即可。

随着时间的推移,你可能声明不再支持某些旧版本的API。申明不支持一个特性并不意味着关闭或者破坏它。而是告诉客户端旧版本的API将在某个特定的时间被删除,并且建议他们使用新版本的API。

一个好的RESTful API会在URL中包含版本信息。另一种比较常见的方案是在请求头里面保持版本信息。但是跟很多不同的第三方开发者一起工作后,我可以很明确的告诉你,在请求头里面包含版本信息远没有放在URL里面来的容易。

三、简洁的API根入口点

无论你信不信,API的根地址很重要。当一个开发者接手了一个旧项目(如进行代码考古时)。而这个项目正在使用你的API,同时开发者还想构建一个新的特性,但他们完全不知道你的服务。幸运的是他们知道客户端对外调用的那些URL列表。让你的API根入口点保持尽可能的简单是很重要的,因为开发者很可能一看到那些冗长而又复杂的URL就转身而走。

这里有两个常见的URL根例子:

https://example.org/api/v1/*
https://api.example.com/v1/*
如果你的应用很庞大或者你预期它将会变的很庞大,那么将API放到子域下通常是一个好选择。这种做法可以保持某些规模化上的灵活性。

但如果你觉得你的API不会变的很庞大,或是你只是想让应用安装更简单些(如你想用相同的框架来支持站点和API),将你的API放到根域名下也是可以的。

让API根拥有一些内容通常也是个好主意。Github的API根就是一个典型的例子。从个人角度来说我是一个通过根URL发布信息的粉丝,这对很多人来说是有用的,例如如何获取API相关的开发文档。

同样也请注意HTTPS前缀,一个好的RESTful API总是基于HTTPS来发布的。

四、减少无谓的限制

当客户端创建了一个请求来获取一个对象列表时,很重要一点就是你要返回给他们一个符合查询条件的所有对象的列表。这个列表可能会很大。但你不能随意给返回数据的数量做限制。因为这些无谓的限制会导致第三方开发者不知道发生了什么。如果他们请求一个确切的集合并且要遍历结果,然而他们发现只拿到了100条数据。接下来他们就不得不去查找这个限制条件的出处。到底是ORM的bug导致的,还是因为网络截断了大数据包?

尽可能减少那些会影响到第三方开发者的无谓限制

这点很重要,但你可以让客户端自己对结果做一些具体的过滤或限制。这么做最重要的一个原因是可以最小化网络传输,并让客户端尽可能快的得到查询结果。其次是客户端可能比较懒,如果这时服务器能对结果做一些过滤或分页,对大家都是好事。另外一个不那么重要的原因是(从客户端角度来说),对服务器来说响应请求的负载越少越好。

四、符合标准的状态码

对于一个RESTful API来说很重要的一点就是要使用HTTP的状态码,因为它们是HTTP的标准。很多的网络设备都可以识别这些状态码,例如负载均衡器可能会通过配置来避免发送请求到一台web服务器,如果这台服务器已经发送了很多的50x错误回来。

1xx范围的状态码是保留给底层HTTP功能使用的,并且估计在你的职业生涯里面也用不着手动发送这样一个状态码出来。

2xx范围的状态码是保留给成功消息使用的,你尽可能的确保服务器总发送这些状态码给用户。

3xx范围的状态码是保留给重定向用的。大多数的API不会太常使用这类状态码,但是在新的超媒体样式的API中会使用更多一些。

4xx范围的状态码是保留给客户端错误用的。例如,客户端提供了一些错误的数据或请求了不存在的内容。这些请求应该是幂等的,不会改变任何服务器的状态。

5xx范围的状态码是保留给服务器端错误用的。这些错误常常是从底层的函数抛出来的,并且开发人员也通常没法处理。发送这类状态码的目的是确保客户端能得到一些响应。收到5xx响应后,客户端没办法知道服务器端的状态,所以这类状态码是要尽可能的避免。

五、完善的API文档

老实说,即使你不能百分之百的遵循指南中的条款,你的API也不是那么糟糕。但是,如果你不为API准备文档的话,没有人会知道怎么使用它,那它真的会成为一个糟糕的API。

让你的文档对那些未经认证的开发者也可用

不要使用文档自动化生成器,即便你用了,你也要保证自己审阅过并让它具有更好的版式。
不要截断示例中请求与响应的内容,要展示完整的东西。并在文档中使用高亮语法。

文档化每一个端点所预期的响应代码和可能的错误消息,和在什么情况下会产生这些的错误消息

如果你有富余的时间,那就创建一个控制台来让开发者可以立即体验一下API的功能。创建一个控制台并没有想象中那么难,并且开发者们(内部或者第三方)也会因此而拥戴你。

另外确保你的文档能够被打印。CSS是个强大的工具可以帮助到你。而且在打印的时候也不用太担心边侧栏的问题。即便没有人会打印到纸上,你也会惊奇的发现很多开发者愿意转化成PDF格式进行离线阅读。

六、提供主流数据格式

目前,大多数“精彩”的API都为RESTful接口提供JSON数据。诸如Facebook,Twitter,Github等等你所知的。XML曾经也火过一把(通常在一个大企业级环境下)。这要感谢SOAP,不过它已经挂了,并且我们也没看到太多的API把HTML作为结果返回给客户端(除非你在构建一个爬虫程序)。

只要你返回给他们有效的数据格式,开发者就可以使用流行的语言和框架进行解析。如果你正在构建一个通用的响应对象,通过使用一个不同的序列化器,你也可以很容易的提供之前所提到的那些数据格式(不包括SOAP)。而你所要做的就是把使用方式放在响应数据的接收头里面。

有些API的创建者会推荐把.json, .xml, .html等文件的扩展名放在URL里面来指示返回内容类型,但我个人并不习惯这么做。我依然喜欢通过接收头来指示返回内容类型(这也是HTTP标准的一部分),并且我觉得这么做也比较适当一些。

你可能感兴趣的:(前端学习【RESTful架构篇】)