浅谈RESTful风格

浅谈RESTful风格

REST风格

RESTRepresentational State Transfer(在表现层上的状态传输)的缩写。

这里翻译一下这句话:

  • 资源(Resources):REST是"表现层状态传输",其实它省略了主语。“表现层"其实指的是"资源"的"表现层”。资源是一个抽象的概念,网络上的一个实体、一段文本、一张图片或者一首歌曲等都是资源。资源总是要通过一种载体来反应它的内容,文本可以用TXT,也可以用HTML或者XML、图片可以用JPG格式或者PNG格式,JSON是现在最常用的资源表现形式。这些资源我们通过URI来定位,也就是一个URI表示一个资源。

  • 表现层(Representation)

    资源是一个具体的实体信息,无法被传输,只能传输资源的表示(representation),把实体展现出来就是表现层,一个资源可以有多种表现,比如HTML、XML、JSON等。具体传输哪种表现取决于服务端的能力和客户端的要求。URI确定一个资源,在HTTP请求的头信息中用Accept和Content-Type字段指定具体表现形式,这两个字段才是对"表现层"的描述。

  • 状态传输(State Transfer)

    访问一个网站,就是客户端和服务器的一个互动过程。在这个过程中,会涉及到数据和状态的变化,而HTTP协议是无状态的,那么这些状态的变化保存在服务器端,所以如果客户端想要通知服务器端改变数据和状态,要通过某种方式来通知它。这种方式只能是只能是HTTP协议,具体来说,就是HTTP协议里面,四个表示基本操作方式的动词:GET、POST、PUT、DELETE。它们分别对应:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。

简单来说:REST就是URI定位资源,客户端和服务器之间,传递这种资源的某种表现层,用HTTP动词(GET,POST,DELETE,DETC)描述操作。

这是一种软件架构风格、设计风格,是一种架构的规范与约束、原则,而不是标准,只是提供了一组设计原则和约束条件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

RESTful架构

基于REST规范构建的API或者说符合REST原则的架构方式就是RESTful架构。

RESTful架构约束

遵守这些约束,从而符合RESTful架构风格,也限制了服务端只能遵循这些约束来处理和响应客户端请求,但是遵循这些约束服务也可以获取理想的非函数化的属性,例如性能、可伸缩、简单程度、可变能力、可见度、灵活性、可信度。

客户-服务器(Client-Server)

第一个约束是基于客户端-服务器架构背后的原则——关注点分离。客户端不关心数据存储,服务器不关心用户界面或用户状态。通过分离用户界面和数据存储这两个关注点,提高客户端代码的可移植性,提高服务器可伸缩性。这种分离对于Web来说更加重要的意义是,只要不改变接口,服务器和客户端也可以独立替换和开发,能够支持大量组织的网络化需求。

统一接口(Uniform Interface)

RESTful架构的核心规范与约束

资源标识:

各种资源都在请求中被确定,例如在使用URI的Web REST系统中,资源本身就表明它们想要被返回给客户端的格式。例如服务端可以从它的数据库发送HTML,XML或JSON格式的数据,即使这些都不是服务端的内部数据格式。

资源操作:

当一个客户端持有一种资源的表述时,包括任何关联的元数据,它都有足够的信息来修改或删除该资源。

信息描述:

每条消息都包含足够的信息来描述如何处理消息。例如,要调用的解析器可以由Internet媒体类型(以前称为MIME类型)指定。响应还明确指出了它们的缓存能力。

超媒体作为应用程序状态的引擎(HATEOAS):

HATEOAS(Hypermedia As The Engine Of Application State)

对于客户端的资源请求,服务器不仅要返回所请求的资源,而且要返回客户端所处的状态和可转移的状态。(客户端有状态)。状态可以简单地理解为客户端展示的数据。可以把客户端比喻成一个状态机,那么这个状态机跳转到一个新的状态,就会显示新的内容。客户端不需要提前知道应用有哪些状态,而是根据服务端响应的“可转移的状态”,提供给用户选择,从而发生状态转移。

用简单的话来说,在严格的RESTful架构中,客户端不需要提前知道服务端的API有哪些、怎么调用,在客户端与服务器通信的过程中,服务端会告诉客户端:在你当前所处的状态下,有哪些API可以使用、可以转移到哪些状态。

因为服务器是无状态的,这就要求客户端在发送请求的时候要携带上足够的信息,让服务器能够判断客户端所处的状态。

例子:10086的“电话自动语音应答服务”,你想要查询你的手机流量,只需要会拨打“10086”,对方会提示你按下哪些按键就能进入哪些状态。进入下一个状态以后,又会有语音提示你接下来能够按哪些按键……最终,你能进入到你想要的那个状态(流量查询服务)。你需要记住的仅仅是“10086”这个号码而已!10086的语音提示相当于Hypermedia,是驱动应用状态转换的“引擎”。

再进一步想想,在RESTful架构中,所有的状态其实就组成了一颗树(更准确地说是网):根节点就是网站的基地址。在你获取一个节点中的资源的同时,服务器还会返回给你这个节点的边:Hypermedia(超链接就是一种Hypermedia)。通过Hypermedia,你能够知道相邻节点的基本信息、地址。结果就是:你能够访问到这颗树的所有节点,而你所需要提前知道的只是“如何到达根节点”而已。每个节点就是一个状态。用户可以在这个状态网中不断跳转。

这种架构的优势非常明显:前后端之间的耦合更加微弱。随着应用功能的升级改变,“树”的样子会大大改变,但是只需要让后端修改返回的资源内容和Hypermedia,前端几乎不用改动。功能的演化更加灵活了。

在REST架构风格中,“传输状态”和“传输资源表示”是同一个意思。客户端所处的状态,是由它接收到的资源表示来决定的。

按照从前往后的顺序梳理一遍:

  1. 客户端请求根资源
  2. 服务器返回根资源的表示,以及相邻资源的Hypermedia
  3. 客户端进入“根资源”状态(比如说,展示首页)
  4. 客户端显示所有相邻状态的Hypermedia供用户选择(比如,在首页有一个导航栏,里面有几个链接)
  5. 用户选择了某个Hypermedia(比如,10086)
  6. 客户端请求“流量查询”
  7. 服务器返回“流量”资源,以及相邻资源的Hypermedia
  8. 客户端进入“流量信息”状态
  9. 客户端显示所有相邻状态的Hypermedia供用户选择(比如,在查询完流量,会提示按1继续查询话费)

不难发现,客户端接收到一个新的资源表示,就会跳转到新的状态,这个过程称为状态传输(服务器给客户端传输新状态)。因此状态传输是通过传输资源表示来完成的。

无状态(Stateless)

RESTful的服务器必须是无状态的,这意味着客户的每一个请求必须包含服务器处理该请求所需的所有信息,URI唯一标识资源,主体包含该资源的状态(或状态更改),若该状态必须跨越多个请求,则根据需要重新发送状态。然后,在服务器进行处理之后,通过标头,状态和响应主体将适当的状态或重要状态的片断传送回客户端。

服务器不能利用任何已经存储的“上下文(context,在这里表示用户的会话状态)”来处理新到来的请求,会话状态只能由客户端来保存,并且在请求时一并提供。

无状态可以实现更高的可伸缩性,因为服务器不必维护,更新或传递该会话状态。此外,负载均衡器不必担心无状态系统的会话亲和性。

状态和资源:状态是服务器关心的,以满足当前会话或请求所需的请求数据。资源是定义资源表示的数据。将状态视为可能因客户端和每个请求而异的数据。资源在请求它的每个客户端都是不变的。

值得注意的是:

  • 服务器不能存储“上下文”不代表连数据库都不能有,“上下文”指那些在服务器内存中的、非持久化的数据。
  • 无状态不代表不能有会话(sessions),无状态仅仅指服务器无状态。服务器不记录、维护会话,但是会话状态可以由客户端在每次请求的时候提供。

无状态的认证机制:

只需要将用户名和密码存储在客户端,然后客户端每次发送请求都附带上用户名和密码。就是将用户名和密码放在HTTP头部中和一个加密的连接(HTTPS)来实现。

如果每次认证,都要去数据库查询用户的信息来核对,那么响应会非常慢,而且服务器也会有很大的性能损失。为了加快认证的速度,最好在内存中使用认证缓存。这并不违背“无状态”的限制,因为缓存的作用仅仅起加速的作用,没有缓存照样能工作。

在这里插入图片描述

缓存(Cache)

客户端和中间层服务器可以缓存响应。因此响应必须直接或间接定义自身是否可被缓存,以免客户端使用过期的响应数据来发送其它请求。良好的缓存策略可以有效减少客户端-服务器之间的交互,进一步提高系统的可伸缩性和性能。

分层系统(Layered System)

客户端通常无法判断它是直接连接到后端服务器,还是中间服务器。中间服务器可通过启用负载平衡,并通过提供共享高速缓存来提高系统的可扩展性。也可以强制执行安全政策。

按需代码(Code-On-Demand,可选)

服务端可以通过传递可执行代码临时为客户端扩展或自定义功能。这方面的例子包括可编译的组件如Java applets和客户机端脚本如Java。

注:REST架构的唯一可选约束是按需代码。如果服务违反任何其他约束,则不能严格地将其称为RESTful。

资源的URL设计

用URL定位资源

RESTful架构风格中,URL用来指定一个资源。资源就是服务器上可操作的实体(可以理解为数据)。例URL/api/users表示的是该网站的所有用户,这是一种资源,可以与之互动(获取、提交、更新、删除)。另外,资源地址具有层次结构,比如/api/users/csr表示用户名为csr的用户,/api/users/csr/blogs表示的所有博客,/api/users/csr/blogs/1234567表示其中的编号(某一标识)为123456的一篇博客。这些都是资源,后者嵌套在前者之中。

既然URL表示一个资源,自然就不应该包含动词,它应该由名词组成。一个 not RESTful 的例子是通过向api/delete/resource发送GET请求来删除一个资源。

操作资源

对某个资源(URL)使用不同的HTTP方法,就代表对这个资源的不同操作:

  • GET(SELECT):从服务器获取资源(一个资源或资源集合)。
  • POST(CREATE):在服务器新建一个资源(也可以用于更新资源)。
  • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
  • PATCH(UPDATE):在服务器更新资源(客户端提供改变的部分)。
  • DELETE(DELETE):从服务器删除资源。
  • HEAD:获取资源的元数据。
  • OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。

GET、HEAD、PUT、DELETE方法是幂等方法。

GET、HEAD方法是安全方法。

幂等方法:对于同一个内容的请求,发出n次的效果与发出1次的效果相同。

安全方法:不会造成服务器上资源的改变。

PATCH不一定是幂等的。PATCH的实现方式有可能是"提供一个用来替换的数据",也有可能是"提供一个更新数据的方法"(比如data++)。如果是后者,那么PATCH不是幂等的。

Method 安全性 幂等性
GET T T
POST F F
PUT F T
PATCH F F
DELETE F T
HEAD T T

返回状态码

  • 200(OK) - 表示已在响应中发出
  • 201(created)- 如果新资源被创建
  • 202(accepted)- 已接受处理请求但尚未完成(异步处理)
  • 204(无内容) - 资源有空表示
  • 301(Moved Permanently) - 资源的URI已被更新
  • 303(See Other) - 其他(如,负载均衡)
  • 304(not modified)- 资源未更改(缓存)
  • 400 (bad request)- 指代坏请求(如,参数错误)
  • 404 (not found)- 资源不存在
  • 406 (not acceptable)- 服务端不支持所需表示
  • 409 (conflict)- 通用冲突
  • 412 (Precondition Failed)- 前置条件失败(如执行条件更新时的冲突)
  • 415 (unsupported media type)- 接受到的表示不受支持
  • 500 (internal server error)- 通用错误响应
  • 503 (Service Unavailable)- 服务端当前无法处理请求

参考博文:
【1】:什么是Rest风格?——深入理解
【2】:详解REST架构风格

发布了18 篇原创文章 · 获赞 16 · 访问量 1050

猜你喜欢

转载自blog.csdn.net/xiaoHui_1126/article/details/104980671
今日推荐