用了那么久的RESTful,还不知道REST是个什么嘛!

1,041 阅读8分钟

前言 :谨以此文纪念一度误以为REST风格简单讲就是POST/DELETE/PUT/GET对应增删改查,URL里面不放add/delete/update的,呵年轻人中那个年轻人的我。

什么是 REST 和 RESTful?

REST -- REpresentational State Transfer,直接翻译为 表现层状态转移。它是一种架构设计风格,描述的是一种客户端与服务端的交互形式,常被概括为” 用 URL 定义资源,用 HTTP 动词描述操作 “;满足这种设计风格的应用程序或设计就被认为是 RESTful 架构风格。

RESTful 是基于资源 ( ROA : Resource-Oriented Architecture ) 的架构。在 ROA 中,处理的对象、任何需要被引用的对象,都是资源。而资源,表现为某个具体的URI。

在 REST 中,客户端与服务端直接的通信,传输的都是资源的表述。这其中涉及到了三个重要的名词 :”资源“、”表述“、”状态转移“。

  • 资源指的是服务器所能提供的数据。 该数据可能是实体数据,也可能是媒体信息,如图片、PDF、文本等各种客户端所需要的数据。
  • 表述指的是资源的某种表示形式。 这个表示不一定是所有信息,可以只是关注的部分信息,而一个信息也可以对应多种表述。例如对于一名在校生,我们可以用他的姓名学号进行定位,也可以用他的位置信息如哪个教室第几排第几个进行定位。
  • 状态转移是对数据的一系列操作。 一个资源可能会随着需求的变化而经历一系列创建、删除、修改,或被查询等过程,客户端通过 REST API 指定请求方法、资源路径和资源表述,对资源的状态进行增删改查,从而引起资源的改变,称为状态转移。

综合以上,客户端通过 REST API 对服务端的资源进行一系列操作,引起资源的状态转移。而这种转移是体现在表述上的,这就是“表述性状态转移”的由来。

为什么要使用 RESTful 架构?

相比于惯常的接口设计思路,REST ful 架构最具优势的一点在于,将系统设计的首要考虑由操作转移到了资源上。

比如说,当我们需要设计一个图书管理系统的时候,我们会想到什么?

  • 添加图书 :/book/add?id=123
  • 删除图书 :/book/delete?id=123
  • 修改图书信息 :/book/update
  • 查找某一本书 :/book/get?id=123
  • 查找某个作者的书籍 :/book/getByAuthor?author=1&page=1

写起来十分顺手,看上去也很符合逻辑,就是需要什么接口就把这个操作翻译成对应的单词嘛!单从应用层面考虑,这样其实也没有太大问题,毕竟对于一些中小型项目来说,更重要的地方在于系统实用性。那如果使用的是 RESTful 风格,这些接口会变成什么样呢?

  • 添加图书 :POST /books/123
  • 删除图书 :DELETE /books/123
  • 修改图书信息 :PUT /books/123
  • 查找某一本书 :GET /books/123
  • 查找某个作者的书籍 :GET /author/1/book?page=1

乍一看只是增删改查与 POST/DELETE/PUT/GET 的对应改造,但它实际展示的是两种完全不同的设计思路。与面向操作的 API 设计风格不同,REST 是面向资源的。资源通过 URI 进行暴露,URI 只需要负责把资源通过合理的方式提供给调用方,具体的操作则通过 HTTP 动词来体现。

最明显的比如说 GET /author/1/book?page=1 相较于 /book/getByAuthor?author=1&page=1 :

author 是资源的一种,所以在查找时,它的 id 被直接放在了 URI 中,即通过访问这个 URI,我们就能直接获取到 id 为 1 的作者的全部书籍信息;而 page 属于资源的附加条件,它是在对资源进行一种过滤操作,所以我们会将它放在请求参数当中。

那么,面向资源的优势在哪里呢?这里可以简单概括为以下几个方面 :

  • 能够使 URL 具有很强的可读性与自描述性
  • 实现了资源描述与视图的松耦合
  • 可提供 OpenAPI,便于第三方系统集成,从而提高互操作性
  • 如果提供无状态的服务接口,可提高应用的水平扩展性

REST 的六大约束是什么?

客户端-服务器约束

该约束基于关注点分离的原则,通过分离用户界面与数据存储这两个关注点,提高了用户界面跨平台的可能性,并通过简化服务器组件,改善系统的可伸缩性。这种分离使得组件能够进行独立修改和扩展,从而能够支持大量组织的网络化需求。

无状态约束

无状态约束条件是指,两次请求之间不存在依赖关系,每一次请求都包含了完整的状态信息。

比如我们要查询工资,如果首先需要登录系统 ( 第一次请求 ),然后输入查询密码 ( 第二次请求 ),当前两次请求均通过时,可以查询到工资,不通过时,报未鉴权的错误;则查询接口的返回结果与前两次请求的状态是相关联的,所以是有状态的服务。

而对于无状态的服务,就可以直接调用查询工资的接口。在客户端发送的请求中 ( 一般是 Header 中 ) 即带有鉴权相关的信息,若服务端判断鉴权通过,则予以查询工资,若不通过则报错。该请求不依赖于任何前置请求,称为无状态。

REST 使用无状态的约束条件,确保了请求的独立性和简单性,减少了很多跨请求的状态的维护成本,但是相对的,也会导致每次请求时可能需要传输更多冗余的信息。

可缓存约束

该约束条件主要可以用于改善网络的效率。缓存约束要求一个请求的响应中的数据被隐式或显式地标记为可缓存或不可缓存的,一面客户端使用过期的响应数据来发送其他请求。良好的缓存策略可以有效减少客户端与服务器之间的交互,从而进一步提高系统的可伸缩性和性能。

分层系统约束

分层系统要求将架构分为若干层,划分每一层的边界,从而降低每一层设计的复杂度。同时,通过分层,可以抽象底层的异构性,给上层提供统一的接口,简化上层的逻辑。

按需代码约束(可选)

按需代码是指,某些场景下,如果客户端不清楚资源的处理方法,就可以通过向服务器请求相应的处理代码来执行。这样可以简化客户端的开发,允许部署后下载功能代码来改善系统的可扩展性。但是,因为传输的是代码,降低了可见性,所以是 REST 的一个可选约束。

统一接口约束

统一接口约束是设计任何 REST 服务的基础。它简化和解耦的架构,使得每个部分可以独立被修改。这个统一的接口中又包含了以下几种具体的约束 :

1. 资源的标识 :

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

2. 通过表述来操作资源

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

3. 自描述的消息

每条信息都包含足够的信息来描述如何处理消息本身,例如一个网络媒体类型本身就顶一个了能运行该媒体的解析器(像是 MIME 类型)。

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

满足 HATEOAS 约束的 REST 服务最大的特点在于服务器提供给客户端的表达中包含了动态的链接信息,客户端通过这些链接来发现可以触发状态转换的动作。

写在最后

重新认真看了一遍概念之后发现之前仿佛写的都是假 RESTful 的我,QAQ。

虽然有这么多约束但是重要的是意识嘛!毕竟有些接口如果完全采用标准的 RESTful 风格,设计起来将非常不便,就比如说登录这种,本身就是一种操作而非资源的需求。所以私心觉得,如果想要设计一个 RESTful 架构风格的系统,可以秉持着面向资源的思想,在不增加系统维护难度的前提下,对某些不方便进行 REST 规约的接口做出变通,从而允许一些“不那么REST”的接口存在。

以上。OvO