但是随着互联网和移动设备的发展,人们对Web应用的使用需求也增加,传统的动态页面由于低效率而渐渐被 HTML + JavaScript(Ajax) 的前后端分离所取代,并且安卓、IOS、小程序等形式客户端层出不穷,客户端的种类出现多元化,而客户端和服务端就需要接口进行通信,但接口的规范性就又成了一个问题:
所以一套结构清晰、符合标准、易于理解、扩展方便让大部分人都能够理解接受的接口风格就显得越来越重要,而 RESTful 风格的接口 (RESTful API) 刚好有以上特点,就逐渐被实践应用而变得流行起来。
现在,RESTful是目前最流行的接口设计规范,在很多公司有着广泛的应用,其中 Github 的 API 设计就是很标准的 RESTful API,你可以参考学习。
在开发实践中我们很多人可能还是使用传统API进行请求交互,很多人其实并不特别了解 RESTful API,对 RESTful API 的认知可能会停留在:
- 面向资源类型的
- 是一种风格
- (误区)接口传递参数使用斜杠(/)分割而不用问号(?)传参。
而其实一个很大的误区不要认为没有查询字符串就是 RESTful API,也不要认为用了查询字符串就不是 RESTful API,更不要认为用了 JSON 传输的 API 就是 RESTful API。
一、REST介绍
REST 涉及一些概念性的东西可能比较多,在实战 RESTful API 之前,要对 REST 相关的知识有个系统的认知。
REST的诞生
REST(英文:Representational State Transfer,简称 REST,直译过来表现层状态转换)是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
它首次出现在 2000 年 Roy Thomas Fielding 的博士论文中,这篇论文定义并详细介绍了表述性状态转移(Representational State Transfer,REST)的架构风格,并且描述了 如何使用 REST 来指导现代 Web 架构的设计和开发。用他自己的原话说:
写这篇文章的目的是:在符合架构原理前提下,理解和评估基于网络的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。
需要注意的是 REST 并没有一个明确的标准,而更像是一种设计的风格,满足这种设计风格的程序或接口我们称之为 RESTful (从单词字面来看就是一个形容词)。所以 RESTful API 就是满足 REST 架构风格的接口。
Fielding 博士当时提出的是 REST 架构在很久的时间内并没有被关注太多,而近些年 REST 在国内才变得越来越流行。下面开始详细学习 REST 架构特征。
REST架构特征
既然知道 REST 和 RESTful 的联系和区别,现在就要开始好好了解 RESTful 的一些约束条件和规则,RESTful 是一种风格而不是标准,而这个风格大致有以下几个主要特征:
以资源为基础 :资源可以是一个图片、音乐、一个 XML 格式、HTML 格式或者 JSON 格式等网络上的一个实体,除了一些二进制的资源外普通的文本资源更多以 JSON 为载体、面向用户的一组数据(通常从数据库中查询而得到)。
统一接口: 对资源的操作包括获取、创建、修改和删除,这些操作正好对应 HTTP 协议提供的 GET、POST、PUT 和 DELETE 方法。换言而知,使用 RESTful 风格的接口但从接口上你可能只能定位其资源,但是无法知晓它具体进行了什么操作,需要具体了解其发生了什么操作动作要从其 HTTP 请求方法类型上进行判断。具体的 HTTP 方法和方法含义如下:
GET(SELECT):从服务器取出资源(一项或多项)。
POST(CREATE):在服务器新建一个资源。
PUT(UPDATE):在服务器更新资源(客户端提供完整资源数据)。
PATCH(UPDATE):在服务器更新资源(客户端提供需要修改的资源数据)。
DELETE(DELETE):从服务器删除资源。
当然也有很多在具体使用的时候使用 PUT 表示更新。从请求的流程来看,RESTful API 和传统 API 大致架构如下:
URI指向资源:URI = Universal Resource Identifier 统一资源标志符,用来标识抽象或物理资源的一个紧凑字符串。URI 包括 URL 和 URN,在这里更多时候可能代指URL(统一资源定位符)。RESTful 是面向资源的,每种资源可能由一个或多个 URI 对应,但一个 URI 只指向一种资源。
无状态:服务器不能保存客户端的信息, 每一次从客户端发送的请求中,要包含所有必须的状态信息,会话信息由客户端保存, 服务器端根据这些状态信息来处理请求。当客户端可以切换到一个新状态的时候发送请求信息, 当一个或者多个请求被发送之后, 客户端就处于一个状态变迁过程中。每一个应用的状态描述可以被客户端用来初始化下一次的状态变迁。
REST架构限制条件
Fielding 在论文中提出 REST 架构的 6 个限制条件,也可称为 RESTful 6 大原则, 标准的 REST 约束应满足以下 6 个原则:
客户端-服务端(Client-Server): 这个更专注客户端和服务端的分离,服务端独立可更好服务于前端、安卓、IOS 等客户端设备。
无状态(Stateless):服务端不保存客户端状态,客户端保存状态信息每次请求携带状态信息。
可缓存性(Cacheability):服务端需回复是否可以缓存以让客户端甄别是否缓存提高效率。
统一接口(Uniform Interface):通过一定原则设计接口降低耦合,简化系统架构,这是 RESTful 设计的基本出发点。当然这个内容除了上述特点提到部分具体内容比较多详细了解可以参考这篇 REST 论文内容。
分层系统(Layered System):客户端无法直接知道连接的到终端还是中间设备,分层允许你灵活的部署服务端项目。
按需代码(Code-On-Demand,可选):按需代码允许我们灵活的发送一些看似特殊的代码给客户端例如 JavaScript 代码。
REST 架构的一些风格和限制条件就先介绍到这里,后面就对 RESTful 风格 API 具体介绍。
二、RESTful API设计规范
既然了解了 RESTful 的一些规则和特性,那么具体该怎么去设计一个 RESTful API 呢?要从 URL 路径、HTTP 请求动词、状态码和返回结果等方面详细考虑。至于其他的方面例如错误处理、过滤信息等规范这里就不详细介绍了。
URL 设计规范
URL 为统一资源定位器,接口属于服务端资源,首先要通过 URL 定位到资源才能去访问,而通常一个完整的 URL 组成由以下几个部分构成:
1 | URI = scheme "://" host ":" port "/" path [ "?" query ][ "#" fragment ] |
- scheme: 指底层用的协议,如 http、https、ftp
- host: 服务器的 IP 地址或者域名
- port: 端口,http 默认为 80 端口
- path: 访问资源的路径,就是各种 web 框架中定义的 route 路由
- query: 查询字符串,为发送给服务器的参数,在这里更多发送数据分页、排序等参数。
- fragment: 锚点,定位到页面的资源
我们在设计 API 时 URL 的 path 是需要认真考虑的,而 RESTful 对 path 的设计做了一些规范,通常一个 RESTful API 的 path 组成如下:
1 | /{version}/{resources}/{resource_id} |
- version:API 版本号,有些版本号放置在头信息中也可以,通过控制版本号有利于应用迭代。
- resources:资源,RESTful API 推荐用小写英文单词的复数形式。
- resource_id:资源的 id,访问或操作该资源。
当然,有时候可能资源级别较大,其下还可细分很多子资源也可以灵活设计 URL 的 path,例如:
1 | /{version}/{resources}/{resource_id}/{subresources}/{subresource_id} |
此外,有时可能增删改查无法满足业务要求,可以在 URL 末尾加上 action,例如
1 | /{version}/{resources}/{resource_id}/action |
其中 action 就是对资源的操作。
从大体样式了解 URL 路径组成之后,对于 RESTful API 的 URL 具体设计的规范如下:
- 不用大写字母,所有单词使用英文且小写。
- 连字符用中杠
"-"而不用下杠"_" - 正确使用
"/"表示层级关系, URL 的层级不要过深,并且越靠前的层级应该相对越稳定 - 结尾不要包含正斜杠分隔符
"/" URL中不出现动词,用请求方式表示动作- 资源表示用复数不要用单数
- 不要使用文件扩展名
HTTP动词
在 RESTful API 中,不同的 HTTP 请求方法有各自的含义,这里就展示 GET, POST, PUT, DELETE 几种请求 API 的设计与含义分析。针对不同操作,具体的含义如下:
1 | GET /collection:从服务器查询资源的列表(数组) |
在非 RESTful 风格的 API 中,我们通常使用 GET 请求和 POST 请求完成增删改查以及其他操作,查询和删除一般使用 GET 方式请求,更新和插入一般使用 POST 请求。从请求方式上无法知道 API 具体是干嘛的,所有在 URL 上都会有操作的动词来表示 API 进行的动作,例如:query,add,update,delete 等等。
而 RESTful 风格的 API 则要求在 URL 上都以名词的方式出现,从几种请求方式上就可以看出想要进行的操作,这点与非 RESTful 风格的 API 形成鲜明对比。
在谈及 GET,POST,PUT,DELETE 的时候,就必须提一下接口的安全性和幂等性,其中安全性是指方法不会修改资源状态,即读的为安全的,写的操作为非安全的。而幂等性的意思是操作一次和操作多次的最终效果相同,客户端重复调用也只返回同一个结果。
上述四个 HTTP 请求方法的安全性和幂等性如下:
| HTTP Method | 安全性 | 幂等性 | 解释 |
|---|---|---|---|
| GET | 安全 | 幂等 | 读操作安全,查询一次多次结果一致 |
| POST | 非安全 | 非幂等 | 写操作非安全,每多插入一次都会出现新结果 |
| PUT | 非安全 | 幂等 | 写操作非安全,一次和多次更新结果一致 |
| DELETE | 非安全 | 幂等 | 写操作非安全,一次和多次删除结果一致 |
状态码和返回数据
服务端处理完成后客户端也可能不知道具体成功了还是失败了,服务器响应时,包含状态码和返回数据两个部分。
状态码
我们首先要正确使用各类状态码来表示该请求的处理执行结果。状态码主要分为五大类:
1xx:相关信息
2xx:操作成功
3xx:重定向
4xx:客户端错误
5xx:服务器错误
每一大类有若干小类,状态码的种类比较多,而主要常用状态码罗列在下面:
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 - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
返回结果
针对不同操作,服务器向用户返回数据,而各个团队或公司封装的返回实体类也不同,但都返回 JSON 格式数据给客户端。
总结
RESTful 风格的 API 固然很好很规范,但大多数互联网公司并没有按照或者完全按照其规则来设计,因为 REST 是一种风格,而不是一种约束或规则,过于理想的 RESTful API 会付出太多的成本。
比如 RESTful API 也有一些缺点
比如操作方式繁琐,RESTful API 通常根据 GET、POST、PUT、DELETE 来区分操作资源的动作,而 HTTP Method 本身不可直接见,是隐藏的,而如果将动作放到 URL 的 path 上反而清晰可见,更利于团队的理解和交流。
并且有些浏览器对 GET,POST 之外的请求支持不太友好,还需要特殊额外的处理。
过分强调资源,而实际业务 API 可能有各种需求比较复杂,单单使用资源的增删改查可能并不能有效满足使用需求,强行使用 RESTful 风格 API 只会增加开发难度和成本。
所以,当你或你们的技术团队在设计 API 的时候,如果使用场景和 REST 风格很匹配,那么你们可以采用 RESTful 风格 API。但是如果业务需求和 RESTful 风格 API 不太匹配或者很麻烦,那也可以不用 RESTful 风格 API 或者可以借鉴一下,毕竟无论那种风格的 API 都是为了方便团队开发、协商以及管理,不能墨守成规。
不同的人对 RESTful API 可能有着不同的理解,但存在即合理,RESTful API 有着其鲜明的优势和特点,目前也是一种 API 设计的主要选型之一,所以掌握和理解 RESTful API 还是相当重要的!




