欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~

本文由sammyshen 发表于云+社区专栏

最近几年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是一对一的关系,其实不是。

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

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

  • 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的一个可选的架构约束条件。

问答

Java中的REST

相关阅读

体验Django REST framework,解读REST架构风格

我是怎么一步步用go找出压测性能瓶颈

当 MySQL 连接池遇上事务(一):神秘的幽灵锁

【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识

此文已由作者授权腾讯云+社区发布,更多原文请点击

搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包!

海量技术实践经验,尽在云加社区

那些年,我们一起误解过的REST的更多相关文章

  1. 【原】谈谈对Objective-C中代理模式的误解

    [原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...

  2. .NET开源进行时:消除误解、努力前行(本文首发于《程序员》2015第10A期的原始版本)

    2014年11月12日,ASP.NET之父.微软云计算与企业级产品工程部执行副总裁Scott Guthrie,在Connect全球开发者在线会议上宣布,微软将开源全部.NET核心运行时,并将.NET ...

  3. 被误解的MVC和被神化的MVVM(转)

    转载自:http://www.infoq.com/cn/articles/rethinking-mvc-mvvm 原文作者:唐巧 被误解的 MVC MVC 的历史 MVC,全称是 Model View ...

  4. Atitit. 构造ast 语法树的总结attilax oao 1. Ast结构树形12. ast view (自是个160k的jar )22.1. 多条语句ast结构22.2. 变量定义 int b,c; 的ast结构22.3. 方法调用meth1(a=1,b=2,c=3);  的ast结构23. 误解的问题33.1. 语法书子能是个二叉树,实际上多叉树越好..33.2. 非要不个ast放到个s

    Atitit. 构造ast 语法树的总结attilax oao 1. Ast结构树形1 2. ast view (自是个160k的jar )2 2.1. 多条语句ast结构2 2.2. 变量定义 in ...

  5. 关于对CSS尺寸单位'em'的长期误解

    一直以来认为'em'是相对于父元素的字体大小. 直到今天学习移动WEB开发,重新复习css的尺寸大小时,惊奇发现:对em深深的误解了!!! 在CSS官网对em的解释实例是: a. h1{line-he ...

  6. 关于分布式事务的一个误解:使用了TransactionScope就一定会开启分布式事务吗?

    背景: 事务是数据库管理系统的一个基本概念,事务具有四个基本特点,即ACID:原子性(Atomicity).一致性(Consistency).隔离性(Isolation)和持久性(Durability ...

  7. CSS魔法堂:你一定误解过的Normal flow

    前言  刚接触CSS时经常听到看到一个词"文档流",那到底什么是"文档流"呢?然后会看到"绝对定位和浮动定位能脱离文档流",从这句可以看到文 ...

  8. 你误解 .net 了吗?

    我现在发现很多人对C#还存在很大的误解,例如C#是完全封闭的,C#不能跨平台,C#性能很差,C#不支持指针等等,持以上观点的人非常多,甚至最近看到的国内某机构对开发语言的统计中还写着C#不跨平台,不开 ...

  9. 对Java垃圾回收最大的误解是什么

    当 我还是小孩的时候,父母常说如果你不好好学习,就只能去扫大街了.但他们不知道的是,清理垃圾实际上是很棒的一件事.可能这也是即使在Java的世界中, 同样有很多开发者对GC算法产生误解的原因--包括它 ...

  10. C++对析构函数的误解(转)

    C++析构前言 析构函数在什么时候会自动被调用,在什么时候需要手动来调用,真不好意思说偶学过C++…今日特此拨乱反正. C++析构误解正文 对象在构造的时候系统会分配内存资源,对一些数据成员进行初始化 ...

随机推荐

  1. TFS文件编码检查机制和修改(Team Foundation Server 2013)

    TFS的版本控制系统会自动按照下面的标准检测代码文件的编码格式: 1. 首先,如果代码文件包含了BOM部分,则使用BOM中制定的编码格式打开文档 什么是BOM (Byte order mark)? h ...

  2. struts1.x和struts2.x之间的一些区别

    转载自http://blog.csdn.net/john2522/article/details/7436307/ struts2不是struts1的升级,而是继承的webwork的血统,它吸收了st ...

  3. JS 面向对象详解

    面向对象详解1 OO1.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...

  4. pageadmin CMS 如何添加自定义页面

    理论上网站上的所有页面都可以通过栏目管理来添加,那自定义页面的意义是什么呢? 网站的需求是很多样化的,比如需要制作一个对外提供数据的api,甚至制作一个搜索页面,或者制作一些数据和栏目没有对应关系的页 ...

  5. Android 的文档翻译

    https://www.cnblogs.com/Xiegg/p/3428529.html -------->media codec的文档翻译

  6. Syncthing源码解析 - 第三方库

    1,AudriusButkevicius/cli 网址:https://github.com/AudriusButkevicius/cli 2,bkaradzic/go-lz4 网址:https:// ...

  7. 2018-2019-2 20165219《网络对抗技术》Exp0 Kali安装 Week1

    2018-2019-2 20165219<网络对抗技术>Exp0 Kali安装 Week1 安装Kali 在官网下载,然后将解压后的文件导入 输入username和password 共享文 ...

  8. [Objective-C语言教程]数据封装(27)

    所有Objective-C程序都由以下两个基本要素组成 - 程序语句(代码) - 这是执行操作的程序的一部分,它们被称为方法(函数). 程序数据 - 数据是受程序功能影响的程序信息. 封装是一种面向对 ...

  9. [转载] 解决gns3 for mac模拟器三层交换机无法成功创建vlan的问题

    1.删除之前导入的ios: 2.选择GNS3--Edit--Preferences--IOS routers--New--导入ios-- 勾选This is an EtherSwitch router ...

  10. 「工具」三分钟了解一款在线流程绘制工具:Whimsical

    Whimsical 是一款在线流程绘制工具,只需要一个浏览器就随时随地绘制精美的流程图.除了流程图(Flowcharts)功能,官方还推出了线框图(Wireframes).便利贴(Sticky Not ...