最近几年REST API越来越流行,特别是随着微服务的概念被广泛接受和应用,很多Web Service都使用了REST API。

REST是HTTP规范主要编写者之一的Roy Fielding提出的,全称是Representational State Transfer,中文可以翻译为表述性状态转移。它不是一种架构,而是一种架构风格。REST提出了一组架构约束条件和原则,任何满足REST约束条件和原则的架构,都称为RESTful架构。

REST虽然流行,但是从业界应用的效果看,良莠不齐。很多系统只是号称是REST API,实际上并没有满足REST的架构约束条件。这些系统按照自己的理解,采用了类似REST API的部分形式(如用GET/POST/PUT/DELETE进行CURD),但更多的是随意设计,搞出了REST-RPC式,甚至是RPC式的API。这样的API,不仅没体现出REST API的优势,反而搞成“四不像”,增加了开发维护成本。

如何理解REST

要规范使用RESTful架构,首先要理解什么是REST。我们可以通过分别理解“表述”“状态转移”来理解REST。

1) 表述

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

所谓表述,指的是资源的某种形式的表示,这个表示不一定是所有信息,可以只是关注的部分信息。并且,同一个资源,可以有多个表述。例如,对于一个景点,可以用jpeg照片来表示,也可以用包含位置、介绍等信息的json或xml格式来分别表示。

在REST中,客户端与服务器之间的通信,传输的都是资源的表述。

2) 状态转移

状态其实应该分为应用状态和资源状态。

应用状态由客户端保存维护,例如会话状态等。客户端通过REST API返回的表述,以及表述中的URI,进行客户端应用状态的转移。

但REST更强调的是资源状态。资源状态存储在服务器端,客户端通过REST API,指定请求方法、资源路径和资源表述(可以包含应用状态),对资源的状态进行增删查改。通过增删查改,引起资源状态的改变,称为状态转移。

3) 结论

结合上面两点,客户端通过REST API对服务器端的资源进行增删查改,引起资源的状态转移。而这种转移是体现在表述上的,所以称为表述性状态转移。

怎样才算是符合REST架构风格

Roy Fielding在他的论文里通过对一个空架构不断追加约束条件,从而推导出了REST架构风格。因此,要想符合REST架构风格,则需要满足对应的约束条件。

image.png

对推导过程感兴趣的朋友可以参考Roy Fielding的论文

REST的约束条件有:

  1. 统一接口
  2. 无状态
  3. 缓存
  4. 客户端-服务器
  5. 分层系统
  6. 按需代码(可选)

其中,统一接口是最直观、也是应用中偏差最大的地方,下面会重点讲解。其余各约束条件则简单讲解。

1. 统一接口

统一接口其实体现在多个方面:

  • 资源URI
  • 请求参数
  • 请求方法
  • 返回码
  • 返回内容
  • ……

1) 资源URI

RESTful架构是基于资源的架构,所操作的一切对象都是资源。因此,需要明确地定位一个资源,而URI技术正好满足这个需求,所以REST中通过URI来定位资源。

资源是一个对象,所以URI中一般只能包含名词(一般是复数),不应该包含动词。当需要定位具体的资源时,URI中一般包含资源的唯一ID。例如:

// 满足REST架构风格的URI
http://www.example.com/books // 所有书籍的资源集合
http://www.example.com/books/123 // ID为123的书籍资源 // 不满足REST架构风格的URI
http://www.example.com/books/query
http://www.example.com/buy

2) 请求参数

因为REST需要通过URI来唯一定位某个(或某种)资源,所以查询资源时,各种资源ID一般是放在URI里面,而不是放在请求参数里面。请求参数中一般放过滤条件分页信息等字段。例如:

// 满足REST架构风格的URI
http://www.example.com/books/123 // ID为123的书籍资源
http://www.example.com/Fielding/books?page=1&per_page=10 // 作者为Fielding的前10本书籍资源集合 // 不满足REST架构风格的URI
http://www.example.com/books?id=123
http://www.example.com/books?author=Fielding

3) 请求方法

REST约定用GET/POST/PUT/DELETE等请求方法来进行CURD操作。但是否使用了GET/POST/PUT/DELETE,并不能作为评判一个系统是否符合REST架构风格的标准。例如,有些系统所有接口都使用GET和POST方法,如果该系统只提供查询和创建操作,那么可能是符合REST架构风格的;但如果该系统还提供修改、删除操作,则该系统不符合REST架构风格。

有些人认为GET/POST/PUT/DELETE跟CURD是一对一的关系,其实不是。

具体的说,各请求方法如下:

  • GET:用于查询资源。
  • POST:用于创建资源。POST方法创建资源的URI由服务器决定,如:POST http://www.example.com/Fieldi...,则是在ID为123的book资源下创建一个某类别资源,如书的评论等,评论的URI也会包含一个服务器生成的ID。
  • PUT:用于创建或修改资源。PUT方法创建资源的URI由客户端决定,如:PUT http://www.example.com/Fieldi...,当ID为123的book资源存在时,将进行修改操作;否则进行创建操作。
  • DELETE:用于删除资源。

另外,还有其他较少用的请求方法,需要注意的是可能部分浏览器不支持。

  • HEAD:用于获取资源的元信息。HEAD方法与GET方法类似,都可以查询资源的元信息(放在HTTP Response的Header),但不会返回资源的表述。例如用于判断资源是否存在。
  • PATCH:用于修改资源。与PUT方法不同的是,PATCH方法只传输改动的部分资源表述,而PUT方法需要传输完整的资源表述。

4) 返回码

REST使用HTTP返回码来表示请求的结果。如果使用规范的REST API,那么根据HTTP返回码就能确定很多信息。常见的HTTP返回码如下:

  • 200(OK):表示请求成功。
  • 201(Created):表示资源创建成功。
  • 204(No content):表示资源为空。
  • 301(Moved Permanently):表示资源的URI已永久性更改,需要在响应内容中获取新的URI。
  • 302(Moved Temporarily):表示资源的URI已临时性更改,需要在响应内容中获取新的URI。
  • 400(Bad Request):表示请求有问题,如参数错误等。
  • 403(Forbidden):表示鉴权不通过,没有权限访问该资源。
  • 404(Not Found):表示资源不存在。
  • 405(Method Not Allowed):表示该资源不支持当前的请求方法。
  • 409(Conflict):表示当前请求的某前置条件不符合。
  • 500(Internal Server Error):通用内部错误。
  • 502(Bad Gateway):网关错误,从上游服务器收到无效响应。
  • 504(Gateway Timeout):网关超时,在预期时间内没有收到上游服务器的响应。
  • ……

还有其他HTTP返回码,可以参考HTTP标准。

只要使用了规范的REST架构风格,那么就可以根据HTTP的标准,做出明确的相应处理,无需另外制定私有协议了。既减少了私有协议的兼容性问题,又能作为标准适用于所有的RESTful架构。

5) 返回内容

REST API的返回内容应该是资源的表述。

前面说过,同一个资源可以有多种不同格式的表述,如json格式和xml格式,所以返回内容应该是自描述的。也就是说,在HTTP响应的Header中,必须包含Content-type属性,如application/json、application/xml、text/html等。

另外,REST是“可编程”的Web服务,也就是说,程序可以根据REST API的返回内容,进行下一步的操作。例如,查询author资源,下一步可能是要查询该作者著作的book资源。所以,如果author资源的表述中包含了该作者著作book资源的URI,则客户端可以进行相应的操作。又如,查询某个地图资源,地图资源的表述中如果包含了各方向的相邻地图资源,则当客户端的鼠标移到屏幕边缘时,就可以获取到该方向上的地图资源了;或者地图资源的表述中包含景点、餐馆等资源URI,则可以进行相应的操作。

在表述中包含其他资源的URI实现了连通性。连通性可以作为客户端应用状态的状态引擎,引导客户端进行下一步的操作,带来了极大的便利。

6) 其他

统一接口还有其他方面的原则,本文就不细讲了,感兴趣的朋友可以阅读Fielding的论文。

2. 无状态

无状态约束条件是指两次请求之间不存在依赖关系,每一次请求都包含完整的状态信息。这里指的状态是指客户端与服务器之间通信交互的状态,与资源状态无关。

举个有状态的例子,为了查工资,需要先登录系统(第一次请求),再输入查询密码(第二次请求)。如果前面两次请求都通过了,那么调用查询接口则可以查询到工资;否则调用查询接口则报未鉴权的错误。查询工资接口的返回结果与前面两次请求的状态是关联的,所以是有状态的服务。

而无状态的服务,则直接调用查询工资接口,在请求中(一般在Header中)带有鉴权信息,若鉴权通过则可查询到工资,鉴权不通过则报错。该请求不依赖于任何前置请求,称为无状态。

REST使用无状态约束条件,确保了请求的独立性和简单性,减少了很多跨请求的状态维护成本。当然,带来的代价是每次请求可能需要传输冗余的信息。

3. 缓存

缓存约束条件主要是用于改善网络的效率。缓存约束条件要求一个请求的响应中的数据被隐式地或显式地标记为可缓存的或不可缓存的。如果响应是可缓存的,那么客户端缓存就可以为以后的相同请求重用这个响应的数据,减少了网络交互,提高了效率、可伸缩性和用户感知的性能。

4. 客户端-服务器

这个约束条件主要是分离用户界面和数据存储,一方面改善用户界面跨平台的可移植性,另一方面简化服务器组件,改善系统的可伸缩性。

5. 分层系统

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

6. 按需代码

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

(转载https://segmentfault.com/a/1190000016313947)了解RestFul Api架构风格设计的更多相关文章

  1. RESTful API 架构解读

    RESTful API 架构解读 首先我们还是先介绍下 RESTful api 的来龙去脉. 首先, RESTful (下文都简称 RESTful api 为 RESTful ) 1.RESTful ...

  2. Restful API 架构与设计参考原则

    1. 什么是RESTREST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移. 它首次出现在2000年Roy Fielding的博 ...

  3. 深入理解 RESTful Api 架构

    转自https://mengkang.net/620.html 一些常见的误解 不要以为 RESTful Api  就是设计得像便于 SEO 的伪静态,例如一个 Api 的 URL 类似于 http: ...

  4. SpringBoot RESTful API 架构风格实践

    如果你要问 Spring Boot 做什么最厉害,我想答案就在本章标题 RESTful API 简称 REST API . 本项目源码下载 1 RESTful API 概述 1.1 什么是 RESTf ...

  5. RESTful api架构设计

    阮老师的这两篇文章足够了 理解 RESTful 架构 RESTful API 设计指南

  6. 使用 Redis 实现排行榜功能 (转载 https://segmentfault.com/a/1190000002694239)

    排行榜功能是一个很普遍的需求.使用 Redis 中有序集合的特性来实现排行榜是又好又快的选择. 一般排行榜都是有实效性的,比如"用户积分榜".如果没有实效性一直按照总榜来排,可能榜 ...

  7. libubox组件(2)——blob/blobmsg (转载 https://segmentfault.com/a/1190000002391970)

    一:blob相关接口 1.数据结构 1: struct blob_attr { 2: uint32_t id_len; /** 高1位为extend标志,高7位存储id, 3: * 低24位存储dat ...

  8. RESTful API架构和oauth2.0认证机制(概念版)

    1. 什么是REST REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移. 它首次出现在2000年Roy Fielding的 ...

  9. 好RESTful API的设计原则

    说在前面,这篇文章是无意中发现的,因为感觉写的很好,所以翻译了一下.由于英文水平有限,难免有出错的地方,请看官理解一下.翻译和校正文章花了我大约2周的业余时间,如有人愿意转载请注明出处,谢谢^_^ P ...

随机推荐

  1. Java HashMap【笔记】

    Java HashMap[笔记] HashMap HashMap 基本结构 HashMap 底层的数据结构主要是数组 + 链表 + 红黑树 其中当链表的长度大于等于 8 时,链表会转化成红黑树,当红黑 ...

  2. 嵌入式Linux可用的防火墙——iptables:实现ip白名单、mac地址白名单

    iptables是linux系统下的一个功能强大的模块,不仅可以用作防火墙,还可以实现NAT等众多路由功能.iptables的容器有很清晰的层次关系: 1. iptables是表的容器,iptable ...

  3. SQL注入的那些面试题总结

    一.知识储备类 1.SQL与NoSQL的区别? SQL:关系型数据库 NoSQL:非关系型数据库 存储方式:SQL具有特定的结构表,NoSQL存储方式灵活 性能:NoSQL较优于SQL 数据类型:SQ ...

  4. 关于XSS简单介绍与waf bypass的一些思路整理

    很久没写东西了,今天整理一点儿思路 简单说一下XSS XSS(cross site script)即跨站脚本,侧重于"脚本"这一层概念,是一种常见web安全漏洞.攻击者通过往web ...

  5. Windows内核基础知识-1-段寄存器

    Windows内核基础知识-1-段寄存器 学过汇编的应该都知道段寄存器,在Windows里段寄存器有很多,之前可能只接触了ds数据段,cs 代码段这种,今天这个博客就介绍Windows一些比较常用的段 ...

  6. 从net到java:MyBatis快速入门

    第一:这不是net与java的对比,只是我学习java相关知识梳理的笔记. 第二:这也没有否认net,只是现在的工作需要自己会java. 第三:这不深入.只是我看了些官网和网上的视频,算是入门的总结. ...

  7. .Net Core 踩坑记录--程序独立发布 无法运行

    背景 创建.net Core3.1 的Console程序 点击发布 选择独立部署模式 目标电脑 Win10 x64 未安装任何.Net SDK 现象 发布的程序 点击运行没有反应 或是直接闪退 解决 ...

  8. Git分支创建命令

    一. 创建test分支提交步骤 1.列出所有分支 # git branch -a 2.创建test分支          # git branch test 3.切换到test分支:         ...

  9. uwp 之资源的访问

    访问image资源 ----------------------------------------------------------------------------- BitmapImage ...

  10. 等待唤醒机制----线程池----lambda表达式

    1.等待唤醒机制 1.1线程间通信 概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同. 比如:线程A用来生成包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的 ...