REST 架构风格详解

什么是 REST 架构风格

REST(Representational State Transfer)是表述性状态转移、分布式超媒体软件的一种架构风格,它基于使用 HTTP、URI 等现有的广泛流行的协议和标准,并由几个核心抽象概念支撑。

简单理解就是,REST 是一种 WEB 应用的架构风格,只要满足 REST 的约束和原则,就能够获得 REST 架构风格所带来的诸多优势。

资源

在REST架构中,“资源”扮演者主要角色。它具有以下特点:

资源是任何可以操作(获取、提交、更新、删除)的数据,比如一个文档(document)、一张图片……资源的集合也是一种资源,比如blogs表示博客(资源)的集合。

进行资源操作的时候,用 URI 来指定被操作的资源。如果一个 URI 不仅能标识一个网络上的资源,还能够定位这个资源,那么这个 URI 也叫 URL 。

表示

资源是一个抽象的概念,资源无法被传输,只能传输资源的表示。一个资源可以有多种表示,比如,一个资源可以用 HTML、XML、JSON 来表示。
具体传输哪种表示取决于服务端的能力和客户端的要求。传输的表示未必就是服务器存储时使用的表示,比如,这个资源在服务器不是以 HTML 或 XML 或JSON 来存储的,可能是一种更加利于压缩的表示。

总的来说,“表示”是“资源”的存储和传输形式,“资源”是“表示”的内容(抽象概念)。不管用什么形式来表示,始终描述的是这个资源。

无状态

根据 REST 的架构限制,RESTful 的服务器必须是无状态的,这意味着来自客户的每一个请求必须包含服务器处理该请求所需的所有信息, 服务器不能利用任何已经存储的“上下文(context,在这里表示用户的会话状态)”来处理新到来的请求,会话状态只能由客户端来保存,并且在请求时一并提供。

无状态让服务器系统的扩展性更强,很方便支持集群和分布式,不用考虑服务器之间的同步 session 状态问题,所以服务器之间的沟通开销很低。

这里注意两点:

  1. 服务器不能存储“上下文”不代表连数据库都不能有,“上下文”指那些在服务器内存中的、非持久化的数据。

  2. 无状态不代表不能有会话(sessions),无状态仅仅指服务器无状态。服务器不记录、维护会话,但是会话状态可以由客户端在每次请求的时候提供。

Token(令牌)认证机制

RESTful 提供的 API 是无状态的,即下一次调用请求与当前的调用请求时完全无关的,但这就无法保证系统资源的安全性。Token (令牌)认证机制就是用来解决无状态和安全性之间的矛盾。
其实现原理如下:

  • 用户发送用户名和密码(一般密码加密),请求验证通过;

  • 服务器判断用户名和密码是否正确

  • 服务器验证通过,返回Token及过期时间

  • 所有请求携带返回的Token在过期时间内即可通过Token验证并使用RESTful API(服务器验证Token时间过期,则无法正常使用RESTful API,需要重新请求验证)

REST 约束与风格

URI 标识资源

每个资源都应该是可标识的,都应该拥有一个明显的 ID。在 Web 中,代表 ID 的统一概念是:URI。URI构成了一个全局命名空间,使用URI标识你的关键资源意味着它们获得了一个唯一、全局的 ID。

操作资源

既然通过 URL 能够定位一个服务器上的资源。那么我们应该如何与这个资源进行互动呢?我们对这个资源 (URL) 使用不同的 HTTP 方法,就代表对这个资源的不同操作:

  • GET(SELECT):从服务器获取资源(一个资源或资源集合)。

  • POST(CREATE):在服务器新建一个资源(也可以用于更新资源)。

  • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。

  • DELETE(DELETE):从服务器删除资源。

通过 HTTP 状态码表示操作的结果

200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
202 Accepted - []:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
401 Unauthorized - [
]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
404 NOT FOUND - [
]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

什么是 RESTful API

RESTful API 就是满足 REST 架构风格的 API,具体而言就是用 URI 定位资源、用 HTTP 标准方法(GET、POST、PUT、DELETE)描述操作,用响应状态码表示操作结果等。

RESTful API 有助于客户端和服务端的功能分离,服务器完全扮演着一个“资源服务商”的角色。各种不同的客户端都可以通过一致的 API 与这个“资源服务商”交流,从而与资源进行互动。

目前互联网公司越来越流行提供 RESTful API 形式服务供第三方调用。

如何设计 RESTful API

在过去不使用 RESTful 架构风格的时候,如果我们要设计一个系统,会以“操作”为出发点,然后围绕它去建设其他需要的东西。

举个例子,我们要向系统中增加一个用户登陆的功能:

  1. 需要一个用户登陆的功能(操作)

  2. 约定一个用于登录的API(也就是URL)

  3. 约定这个API的使用方式(发送响应什么数据、格式是什么)

  4. 前后端针对这个API进行开发

这种设计方式有如下缺点:

  1. 当我们不断为这个系统增加操作,每增加一个操作都要按照上面的流程设计一次,第 2 和 3 点的工作实际是可以大大削减的(通过 REST )。

  2. 操作之间可能是有依赖的,依赖多起来,系统会变得很复杂。

  3. 我们的 API 缺乏一致性(需要一份庞大的文档来记录 api 的地址、使用方式)。

  4. 操作通常被认为是有副作用(Side Effect)的,很难使用缓存技术。

而如果我们设计 REST 风格的系统,资源是第一位的考虑,首先从资源的角度进行系统的拆分、设计,而不是像以往一样以操作为角度来进行设计。

用两个例子来说明:银行的转账 API 和 即时通讯软件中发送消息的 API。

这两个功能非常具有“动作性”,看起来和“资源”联系不大,很容易就会设计成 not RESTful 的 API:POST /transfer/${amount}/to/${toUserID}、POST /api/sendMessage。

一旦在 URL 中引入了动词,这个URL的功能就定死了,无法用于别的用途(比如,GET /transfer/${amount}/to/${toUserID}或GET /api/sendMessage的语义很奇怪,不好使用)。并且,不同功能的API有各自的结构,一致性很差,需要一份详细的API文档才能使用。

这种情况下,要如何通过 RESTful 架构风格,设计一套一致、多用途的 URL 呢?

简单地说,就是将一个“动作”理解为“操作一个资源”。这里的“操作”是指HTTP的方法。

对于转账动作,就可以理解为“新建一个转账事务”(转账事务是资源),因此 API 就可以设置成这样: POST /transactions,请求体为:to=632&amount=500。这样的设计不但简洁明了,而且我们可以将这个URL用于别的用途:通过GET /transactions来获取该用户的所有转账事务。还可以将GET /transactions/456828定义为“获取某一次转账记录”。

即时通讯软件中发送消息的动作,我们可以理解为“操作聊天记录(聊天记录是资源,它是由“消息”组成的集合,消息也是资源)”,所以 API 设计为

POST /messages # 创建新的聊天记录(body传输消息的内容)
GET /messages # 获取聊天记录(返回一个数组,其中每个项是一个消息)
GET /messages/${messageID} # 获取某个消息的详细信息
PUT /messages/${messageID} # 更新某个消息(body传输消息的内容)
DELETE /messages/${messageID} # 删除某个消息的记录

从以上的两个例子我们可以看出,使用 RESTful 风格可以克服传统架构风格的 4 个缺陷:

  1. 设计API工作量减少,因为功能需求一旦出来,需要操作的资源、操作的方式立刻就能分析出来,因此资源URL和API的使用方式(GET, POST...)都很容易得到。

  2. 没有了操作之间的依赖。资源之间虽然可能有关联,但是小得多。

  3. 对资源的操作也就那么几种(获取、新建、修改、删除),API的一致性、自我描述性很强,不需要过多解释。

  4. 对于GET请求,我们都可以考虑使用缓存,因为在RESTful的架构中,GET请求代表获取数据,必须是安全、幂等的。

总结

REST 是一种软件架构风格,使用 REST 架构风格的软件架构具有很强的演化、拓展能力。

posted @ 2020-10-19 18:51  Binge-和时间做朋友  阅读(873)  评论(0编辑  收藏  举报