先后端分离开发,RESTful 接口应该这样设计

译者 | 唐尤华 html

https://dzone.com/refcardz/rest-foundations-restfuljava

前言web

REST(Representational State Transfer)架构风格是一种世界观,把信息提高为架构中的一等公民。经过 REST 能够实现系统的高性能、可伸缩、通用性、简单性、可修改性和可扩展等特性。这篇文章解释了主要的 HTTP 操做,对 HTTP 响应码进行描述,并列举相关开发库和框架。此外,本文还提供了额外的资源,对每一个主题进行了更深刻的探讨。express

1. 简介编程

REST 架构风格不是一种能够购买的技术,也不是一个能够添加到软件开发项目中的开发库。首先也是最重要的,REST 是一种世界观,把将信息提高为构建架构中的一等公民。json

Roy Fielding 的博士论文“架构风格和基于网络的软件架构设计”介绍和整理了“RESTful”系统的思想和相关术语。这是一篇学术论文,虽然使用正式语言,可是仍然易于理解而且提供了实践基础。api

总结一下,RESTful 经过体系结构的特定选择能从部署的系统中得到理想特性。尽管这种风格定义的约束细节并无为全部场合设计,可是的确能够普遍适用。浏览器

因为 Web 对消费者偏好有多重影响,REST 风格的倡导者鼓励企业组织在其边界内使用相同原则,就像他们在面向外部客户的网页上作的那样。本文将讨论现代 REST Web 实现中的基本约束和属性。缓存

1.1 基础概念安全

REST 表示什么含义?以无状态方式传输、访问和操做文本数据。当正确部署后,REST 为互联网上不一样应用程序之间提供了一致的互操做性。无状态(stateless)这个术语相当重要,它使得应用程序能够用不可知的方式进行通讯。RESTful API 经过统一资源定位符地址(URL)公开服务。URL 名称将资源的区分为接受内容或返回内容。RFC 1738 中定义了 URL scheme,能够在这里找到: https://tools.ietf.org/rfc/rfc1738.txt

RESTful URL 相似于下面这个 library API:http://fakelibrary.org/library

实际公开的不必定是某种任意的服务,而是表明对消费者有价值的信息资源。URL 做为资源句柄,能够请求、更新或删除内容。

开始把服务发布到某个地方,而后开始与 REST 服务进行交互。返回的内容多是 XML、JSON 格式,或者更确切地说是像 Atom 或自定义 MIME 类型等超媒体格式。虽然通常建议尽量重用现有的格式,可是对正确设计的媒体类型正在变得愈来愈宽容。

须要请求资源的时候,客户机会发一个超文本传输协议(HTTP)GET 请求,例如在浏览器中键入一个 URL 而后点击回车,选择书签,或者点击锚引用连接。

经过编程方式与 RESTful API 交互,有数十个客户端 API 或工具可供选择。使用 curl 命令行工具,能够输入如下命令:

curl http://fakelibrary.org/library

上面的命令使用默认格式,但你可能不须要这种格式的信息。幸运的是 HTTP 有一种机制,能够指定返回信息的格式。在请求中指定 "Accept" 头,若是服务器支持这种格式,会以指定的格式返回。这个过程称为内容协商,这是 HTTP 中未被充分利用的功能之一,可使用一个相似于上面例子中的 curl 命令来指定:

curl –H "Accept:application/json" http://fakelibrary.org/library

因为资源名称与内容格式是独立的,从而让请求不一样格式信息成为可能。虽然 REST 中的 “R” 的含义是 “表现”而非“资源”,可是应该在构建系统时容许客户端指定请求的内容格式,请牢记这一点。在咱们的例子中 library API 可能包含如下 URL:

一、http://fakelibrary.org/library:图书馆基本信息,搜索图书、DVD等相关资源基本功能的连接。

二、http://fakelibrary.org/book:存放书籍的“信息空间”。从概念上说,这里可能会存放全部的书籍。显然,若是这个问题获得解决,咱们不会但愿返回全部图书,而是但愿经过类别、搜索关键词等来检索图书。

三、http://fakelibrary.org/book/category/1234:在书籍的信息空间里,咱们能够指定类别浏览,例如成人小说、儿童书籍、园艺书籍等。使用杜威十进制图书分类法是可行的,但咱们也能够想象自定义分组。问题的关键在于,这种“信息空间”多是无限的,并且可能收到人们实际关心的信息类型影响。

四、http://fakelibrary.org/book/isbn/978-0596801687:提到某本具体的书,应该包括书名、做者、出版商、系统中的拷贝数、可用拷贝数等信息。

译注:杜威十进制图书分类法由美国图书馆专家麦尔威·杜威发明,于1876年首次发表,历经22次的大改版。该分类法以三位数字表明分类码,共可分为10个大分类、100个中分类及1000个小分类。

就图书馆用户而言,上面提到的这些 URL 可能就是只读的,可是图书馆员使用应用程序时实际上能够操做这些资源。

例如添加一本新书,能够向 main/book 地址 POST 一个 XML。使用 curl 提交,看起来可能像这样:

curl –u username:password -d @book.xml -H "Content-type: text/xml" http://fakelibrary.org/book

此时,服务器可能会对提交的内容进行校验,建立与图书相关的记录,并返回响应代码201——表示已建立新资源。新资源的 URL 能够在响应的 Location 头中找到。

RESTful 请求一个重要特性:每次请求都包含了充足的状态信息来响应请求。这为服务器的可见性和无状态创造了条件,并为扩展系统和识别发送的请求内容提供了理想特性。对于缓存结果也很是有帮助。服务器地址和请求状态组合成可计算的 hash 键值,并造成一个结果集:

http://fakelibrary.org + /book/isbn/978-0596801687

接下来咱们会先介绍 GET 请求。客户端在须要时发出 GET 请求获取指定资源。客户端能够在本地缓存请求结果,服务器能够在远程缓存结果,系统的中间层能够在请求链路中间缓存结果。这是一个与具体应用程序无关的特性,能够加入系统设计中。

正由于能够操做资源,也就意味着并非每一个人均可以这样作。咱们彻底能够创建一个防御模型,要求用户在操做前验证身份,证实他们具备该操做的受权。在本文的最后,将提供一些提高 RESTful 服务安全性的内容。

2. REST Vs SOAP

SOAP:简单对象访问协议(Simple Object Access Protocol)。是交换数据的一种协议规范,是一种轻量的、简单的、基于XML的协议。一条 SOAP 消息就是一个普通的 XML 文档,包含必需的 Envelope 元素、可选的 Header 元素、必需的 Body 元素和可选的 Fault 元素。

把 REST 与 SOAP 划等号是错误的。在这二者之间进行比较,带来的困扰远多于好处。简单来讲,它们不是一回事。尽管能够用这两种方法解决许多架构问题,可是它们不能相互替换。

这种混淆很大程度上源于对 “REST 是经过 URL 调用 Web 服务”这句话的误解。这种观点与 RESTful 架构的功能相距甚远。若是不全面深刻理解 RESTful 的架构实现,就很容易误解 REST 实践的本意。

利用 REST 的最佳方式,是将生产和消费过程当中的信息与技术分离实现解耦,进而更好地管理系统,让架构具有如下特性:

一、高性能

二、可扩展

三、通用

四、简洁

五、可修改

这并非说,基于 SOAP 构建的系统不能具有上述特性。而是当技术、组织或过程的复杂性形成不能在单个事务中完成请求的生命周期时,这种状况 SOAP 可以发挥最佳效果。

3. Richardson 成熟度模型

Leonard Richardson 引入了一种成熟度模型,部分阐述了 SOAP 与 REST 之间的区别,并提供一种对不一样类型的系统进行分类的框架。许多人不恰当地称之为 “REST”。能够将这种分类看做系统中不一样 Web 技术组件紧密程度的度量标准:包括信息资源、HTTP 做为应用层协议和做超媒体做为控制媒介。

称其为“成熟度模型”彷佛意味着应该只构建“成熟度”最高的系统。这种见解是不合适的。第 2 级是有价值的,从 2 级向 3 级转变一般只是采用了一种新的 MIME 类型。然而,从 0 级到 3 级的转变要困可贵多,所以增量式升级转变一般也会增值。

首先,肯定但愿公开哪些信息资源。采用 HTTP 做为处理这些信息资源的应用协议,包括内容协商。接下来,当一切就绪时,使用基于超媒体的 MIME 类型,这样就能够充分享受 REST 的好处了。

4. 动词

动词是用来与服务器资源交互的方法或操做。RESTful 系统中有限的动词让刚接触该的使用者感到困惑和沮丧。看似武断和没必要要的约束,目的是鼓励以应用程序无关的形式提供可预测的行为。经过明确、清晰地定义这些动词的行为,客户端能够在网络中断或故障时自主处理。

精心设计的 RESTful 系统主要使用 4 个 HTTP 动词。

4.1 GET

GET 请求是最经常使用的 Web 动词。GET 请求将命名资源从服务器传输到客户端。尽管客户端不须要知道请求的资源内容,可是请求返回的结果是带元数据标记的字节流,这代表客户端应该知道如何解释资源。在 Web 中一般用 “text/html” 或 “application/xhtml+xml” 表示。正如以前提到的那样,只要服务器支持,客户端能够经过内容协商提早指定请求的返回格式。

GET 请求关键点之一,不要修改服务器端的任何内容。这是一个基本的安全要求,也是不熟悉 REST 的开发者犯的最大错误之一。你可能会遇到这样的 URL:

http://example.com/res/action=update?data=1234

不要这样作! 因为 GET 请求安全性容许缓存请求,这会让正在构建的 RESTful 系统陷入混乱。GET 请求也意味着幂等性,即屡次请求不会对系统产生任何影响。这是基于分布式基础设施的一个重要特性。若是进行 GET 请求时被打断,因为幂等性,客户端能够再次发起请求。这点很是重要。在设计良好的基础结构中,客户端能够从任意应用程序发起请求。虽然必定会有与应用程序相关的特定行为,可是加入与应用程序无关的行为越多,系统就会越有弹性,也更容易维护。

4.2 POST

在辨别 POST 和 PUT 动词意图的时候,状况开始变得不那么清晰。根据定义,两者彷佛均可以被客户端用来建立或更新服务器资源,然而它们的用途各有不一样。

当没法预测请求建立的资源的标识时,客户端会使用 POST 请求。在新增雇员、下订单或提交表单的时候,咱们没法预测服务器将如何命名正在建立的资源。这就是为何将资源提交给相似 Servlet 这样的程序处理。接下来,服务器会接受请求、校验请求、验证用户凭据等。成功处理后,服务器将返回 201 HTTP 响应代码,其中包含一个 “Location” 头,表明新建立的资源的位置。

注意: 有些人将 POST 视为建立资源的 GET 会话。他们会对建立的资源经过 body 返回200,而不是返回 201。这彷佛是避免二次请求的一种快捷方式,可是这种作法混合了 POST 和 GET,让缓存资源的潜在影响变得微妙。尽可能避免由于走捷径而牺牲大局。短时间看这彷佛是值得的,但随着时间的推移,这些捷径叠加起来可能会带来不利的影响。

POST 动词的另外一个主要用途是“追加(Append)”资源信息,即增量编辑或部分更新,而不是提交完整的资源。这里应使用 PUT 操做。对已知资源使用 POST 更新,可用于向订单添加新送货地址或更新购物车中某个商品的数量。

因为是更新资源的部分信息,POST 既不安全也不幂等。

POST 的最后一种常见用法是提交查询。将查询的内容或表单内容进行 URL 编码后提交给服务执行查询。一般能够直接返回 POST 结果,由于没有与查询相关的标识。

注意: 建议将这样的查询转换为信息资源自己。若是采用 POST 查询,能够考虑采用 GET 请求,后者支持缓存。你能够与其余人分享这个连接。

4.3 PUT

因为 HTML 表单目前还不支持 PUT,许多开发人员基本上会忽略 PUT 动词。然而,PUT 有一个重要做用而且是 RESTful 系统完整愿景的一部分。

客户端能够向指定 URL 发 PUT 请求,服务器用请求中的数据执行覆盖操做。PUT 请求在某种程度上是等幂的,而 POST 更新不是。

若是客户端在 PUT 覆盖请求时被打断,因为从新发送覆盖操不会形成任何后果,所以能够再次发送。客户端具有管理状态能力,因此直接重发覆盖命令便可。

注意: 这种协议层处理并不意味着要取消更高级别(如应用层)的事务,可是一样地,它也是一种体系结构上理想的属性,能够在应用层如下使用。

若是客户端可以提早了解资源的标识,那么 PUT 也可用于建立资源。正如咱们在 POST 部分中讨论的那样,一般不会出现这种状况。可是若是客户端可以控制服务器端信息空间,那么这种操做也是合理的。

4.4 DELETE

在公共网络上 DELETE 动词没有被普遍使用(谢天谢地!)。然而,对于控制信息空间很是有用,它是资源生命周期中很是有用的一部分。

DELETE 请求意在实现等幂。可能因为网络故障 DELETE 请求被打断,这时咱们但愿客户端继续尝试。第一次请求不管成功与否,资源都应该返回204(无指定内容)。对以前已删除的资源或不存在的资源可能须要一些额外处理,两种状况都应该返回404。一些安全策略要求为不存在的和已删除的资源返回404,这样 DELETE 请求就不会泄漏有关资源是否存在的信息。

还有另外三个没有普遍使用可是有价值的动词。

4.5 HEAD

HEAD 动词用来请求资源,但不实际检索。客户端能够经过 HEAD 检查资源是否存在,并检查资源相关的元数据。

4.6 OPTIONS

OPTIONS 动词也能够用来查询服务器相关资源的状况,方法是询问哪些其它动词可用于该资源。

4.7 PATCH

最新的动词 PATCH 直到 2010 年才正式采纳为 HTTP 的一部分。旨在提供一种标准化方式来表示部分更新。PATCH 请求经过标准格式让交互的意图更明确。这是推荐使用 PATCH 而非 POST 的缘由,尽管 POST 能够用于任何事情。IETF 发布了 RFC 文档,定义用于 PATCH 操做的 XML 和 JSON。

若是客户端 PATCH 请求的 header 中带 If-Match,则此部分为幂等更新。能够重试中断的请求,由于若是第一次请求成功,那么 If-Match header 会不一样于新状态。若是相同,则未处理原始请求可应用 PATCH。

5. 响应码

HTTP 响应码为咱们在客户端和服务器之间的对话提供了丰富的请求状态信息。大多数人只熟悉通常意义上的200、40三、404或者500,可是还有更多有用的代码可供使用。这里表格并不全面,可是它们涵盖了许多在 RESTful 环境中应该考虑使用的最重要代码。数字可按照如下类别分组:

一、1XX:信息类

二、2XX:操做成功

三、3XX:重定向

四、4XX:客户端错误

五、5XX:服务器错误

第一组响应码代表客户端的请求格式正确且处理成功。具体操做以下表所示:

表1 成功的客户端请求

表2 — 客户端重定向请求

表 3 中的响应代码表示客户端请求无效,若是条件不发生变化,从新请求仍没法处理。这些故障可能有请求格式错误、未受权的请求、请求的资源不存在等。

表3 客户端请求错误

最后,表4中的响应代码表示服务器暂时没法处理客户端请求(可能仍然无效)。客户端应当在未来的某个时候从新请求。

表4 服务器处理请求错误

服务根据其自身功能要求具备不一样程度的可扩展性。

注意:试试响应代码 418,它会返回简洁有力的回复:"我是一个茶壶。"

5.1 REST 资源

5.1.1 论文

Fielding 博士的论文《架构的风格与基于网络的软件架构设计》是对 RESTful 思想的主要介绍:http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

5.1.2 RFC 规范

REST 常见用法的技术规范由**国际互联网工程任务组(IETF)定义,按照请求评议(RFC)**流程完善。规范由数字定义,并随着时间推移不时更新版本,以替换已通过时的文件。目前,这里有最新的相关 RFC 文件。

5.1.2.1 URI

RFC 3986 定义了 URI 命名方案的通用语法。URI 是一种命名方案,包含了对其余如网址、支持名字子空间等编码方案。网址:http://www.ietf.org/rfc/rfc3986.txt

5.1.2.2 URL

Url 是 URI 的一种形式,其中嵌入了充足的信息(一般是访问方案和地址),用于解析和定位资源统一资源定位符。网址:http://www.ietf.org/rfc/rfc1738.txt

5.1.2.3 IRI

国际化资源标识符(IRI)在概念上是一个用 Unicode 编码的 URI,用于在 Web 上使用的标识符中支持世界上各类语言的字符。IETF 选择建立一个新的标准,而不是改变 URI 方案自己,以免破坏现有的系统并明确区分这两种方法。那些支持 IRI 的人故意这样作。还定义了在 IRI 和 URI 之间进行转换的映射方案。网址:http://www.ietf.org/rfc/rfc3987.txt

5.1.2.4 HTTP

HTTP 1.1 版本定义了一个应用程序协议,用于操做一般以超媒体格式表示的信息资源。虽然它是一个应用级协议,但一般不与应用程序绑定,由此产生了重要的体系结构优点。大多数人认为 HTTP 和超文本标记语言文(HTML)就是“Web”,可是 HTTP 在非面向文档的系统开发中也颇有用。网址:http://www.ietf.org/rfc/rfc2616.txt

5.1.2.5 PATCH 格式

JavaScript 对象表示法(JSON)Patch 网址:https://www.ietf.org/rfc/rfc6902.txt

XML Patch 网址:https://www.ietf.org/rfc/rfc7351.txt

5.2 描述语言

人们对使用各类语言来描述 API 很是感兴趣,经过描述语言能够更容易地编写客户端和服务器文档,甚至生成骨架代码。一些比较流行、有趣的描述语言包括:

5.2.1 RAML

RAML 是一种 YAML/JSON 语言,能够定义 2 级成熟度的 API。它支持可重用模式和特性,经过模式和特性实现功能 API 设计的标准化。网址:http://raml.org

5.2.2 Swagger

Swagger 是另外一种 YAML/JSON 语言,支持定义2级成熟度的 API。它包含代码生成器、编辑器、 API 文档可视化功能,可以与其余服务集成的。网址:http://swagger.io

5.2.3 Apiary.io

Apiary.io 是一个协做式的托管站点。它支持 Markdown 格式的 API 文档,能够围绕设计过程进行社交,而且支持模拟数据的托管实现,以便于在 API 实现以前对其进行测试。网址:http://apiary.io

5.2.4 Hydra-Cg

Hydra-Cg 是一种超媒体描述语言,经过像 JSON-LD 这样的标准方便地实现数据关联和并其它数据源的交互。网址:http://www.hydra-cg.com

5.3 实现

有一些用于构建、生成和使用 RESTful 系统的库和框架。虽然任何 Web 服务器均可以配置成提供 REST API,但有了这些框架、库和环境可让过程变得更容易。

如下概述了一些主流的环境:

5.3.1 JAX-RS

JAX-RS 规范为 JEE 环境增长了对 REST 的支持。网址:https://jax-rs-spec.java.net

5.3.2 Restlet

Restlet API 是构建用于生产和消费 RESTful 系统的 Java API 先行者之一。它专一于为客户端和服务器生成一些很是干净、强大的 API。

Restlet Studio 是一个免费工具,可以在 RAML 和基于 swagger 的 API 描述之间进行转换,支持 Restlet、 Node 和 JAX-RS 服务器和客户端的骨架和 Stub 代码。网址:http://restlet.org

5.3.3 NetKernel

Netkernel 是一个比较有趣的 RESTful 系统。它基于微内核,是支持各类架构风格环境的表明。Netkernel 受益于在软件体系结构中采用 Web 的经济属性。你能够把它想象成“在内部引入 REST”。虽然任何基于 REST 的系统在外面看起来都同样,但在运行环境内部 NetKernel 看起来也同样。网址:http://netkernel.org

5.3.4 Play

两个主要的 Scala REST 框架之一。网址:https://www.playframework.com

5.3.5 Spray

两个主要的 Scala REST 框架之一。它设计成配合 Akka actor 模型一块儿工做。网址:http://spray.io

5.3.6 Express

两个主要的 Node.js REST 框架之一。网址:http://expressjs.com

5.3.7 hapi

两个主要的 Node.js REST 框架之一。网址:http://hapijs.com

5.3.8 Sinatra

Sinatra 是一个领域特定语言(DSL),用来在 Ruby 中建立 RESTful 应用程序,网址:http://www.sinatrarb.com

5.4 客户端

经过浏览器调用 REST API 是可行的,可是还有其它客户端可用于测试和构建面向资源的系统。

5.4.1 curl

curl 是流行的库和命令行工具之一,支持在各类资源上调用各类协议。网址:https://curl.haxx.se

5.4.2 httpie

httpie 是一个很是灵活和易用的客户端,支持经过 HTTP 与资源进行交互。网址:https://httpie.org

5.4.3 Postman

健全的 API 测试须要可以捕获和重播请求,支持各类身份验证和受权方案等功能。之前的命令行工具容许这样作,但 Postman 是一个较新的桌面应用程序,让这些工做对于开发团队来讲变得更容易。网址:https://www.getpostman.com

 


-END-

若是看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「web_resource」关注本订阅号,欢迎添加小编微信「focusoncode」,每日朋友圈更新一篇高质量技术博文(无广告)。

扫描二维码添加小编↓

1. Spring Boot + Vue 如此强大?

2. 程能力与编程年龄

3. 安利一款 IDEA 中强大的代码生成利器

4. 如何获取靠谱的新型冠状病毒疫情