深度理解RESTful设计

REST的含义

REST是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格,它不仅可应用于Web服务设计,但目前来说其最流行的领域便是WebRESTful则是基于HTTP语义化的设计风格,它并不是一种“标准”,只要设计者遵循RESTful的设计规范,开发过程和应用便能享受到其带来的好处,但接口设计往往不是一尘不变的,有时候违反RESTful规范的设计可能会带来更多便利(但这并不意味着不去遵守,而是应该将设计实现得更灵活)。下面提出REST得解释:

单词拆分含义
Resources资源(互联网得一切视作资源)
Representational标志性(资源的表现层)
State Transfer状态转移(服务器数据的改变)

以上是REST本身得释义,我们将再下文详细讲述根据其含义如何设计标准的RESTful接口。

1.以资源为中心

我们将网络上的一切视资源,无论是图片、视频、文本还是链接、商品,都将他们当作资源。也正是基于这点,RESTful设计一切以资源为中心,设计原则对应着接口为名词表述形式,接口不能出现动词。

http://localhost/users

一般接口资源对象也对应着数据库中的某张数据表,例如上述接口对应数据库存在一张user表,开发围绕其进行增删改查操作,由于数据表多为数据集合,因此常常用复数形式体现。
相比于传统接口设计,RESTful风格接口围绕资源本身展开,资源和操作分离,更便于开发时资源的管理。

2.资源抽象

接口资源与数据库资源一一对应的情况是常见的,但这并不意味着所有资源都可以映射为数据库表资源。比如前端向后台请求视频格式资源,但开发中我们不会将庞大的视频资源以二进制文件形式(LONG_BLOB)存储于数据库,如果这样做将导致IO负担严重加大,数据库读写性能变差;常规做法是将视频资源存放于图片视频资源服务器,用地址去请求资源,因此数据库应不该存在对应着的视频资源数据表,而是视频链接表,由后端自己请求获取后传前台。对于没有资源对应表情况下的名词设计,我们采用抽象方法来完成名词塑造,例如请求视频资源的格式可以是这样的:

http://localhost/videos

3.资源多样的表现层

传统的接口对于表现层的请求常常会在地址栏上体现,例如:

http://localhost/userinfo.json?userid=20191129 

如此,该接口希望后端返回数据的格式以JSON字符串形式,这样的写法是前后的一致讨论的结果,一定程度上复杂化了接口的表达,为此RESTful提供了新的表现层约束方式,是Http协议的规范,更利于敏捷开发(Agile software development),也正是REST含义中Representational单词的释义。

对于Representational的释义体现在其传输内容的表现,资源在网络传输中可以有各种形式的表现,可以是图片、视频也可以是普通文本、JSON字符串,在web应用中我们可以设置请求头(Request Headers)和响应头(Response Headers)来约束内容形式,打开浏览器查看Network模块,当有请求发送时,我们可以观察请求头和响应头与响应头中的参数,在请求头中包含Accept参数(该参数仅在请求头中存在),意为返回内容的MIME格式AcceptContentType在请求头和响应头中都可以存在,表示数据在网络中传输的MIME格式ContentType就此两者约束着内容在传输过程中的表现形式,也即Representational
MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的因特网标准: W3C手册

4.数据状态转移

对于Web开发来说,对Http协议可谓时重度依赖,但Http众所周知是无状态协议,几次请求之间无法建立关联,因此数据的状态全部都存在于后端服务器,主要表现在数据库的信息存储,因此接口的作用除了获取数据外,还可以改变后端数据的状态,因此接口调用产生的结果可以使数据发生状态转移。

5.资源接口设计

接口的设计是基于以上几点原则的,剩下的便是请求方式和返回值的处理

  • 请求方式与操作
请求方式操作
GET获取资源
POST创建资源
PUT修改资源整体
PATCH修改资源元参数
DELETE删除资源
HEAD获取资源元数据
OPTIONS获取资源API

以上就是Http1.1协议提供的 7 种请求方式,被划线的操作并非不可用,而是不常用,一般我们基于前面 5 种请求方式做操作指令,例如我们要查询3号用户的信息

GET http://localhost/users/3

修改3号员工的一些信息

PUT http://localhost/users/3?age=25&phoneNum=135xxxxxxxx

删除3号员工信息

DELETE http://localhost/users/3

注意:当传输内容很多的情况下,我们可以通过表单传参的方式向后端传参数,例如创建资源(比如注册)一般我们使用表单传参,这样不会使URI过度复杂且不会暴露参数。

  • 操作与返回参数及状态码
操作返回内容(状态码)
增加新建资源完整对象(201)
删除空内容(No Content)(204)
修改修改资源完整对象(201)
查询查询资源(200)

以上是RESTful规范规定的返回值与状态码,这也是基于Http协议2xx的返回码规范,但这并不意味着所有的接口都要设计成标准的RESTful风格接口,有时候返回值和返回状态码的设计可以参考传统接口设计,成功即200。遵守规范的好处自不用多说,增强了接口的自述性

6.抽象接口方法

基于以上几点我们已经可以设计出基础的RESTful风格API,但实践过程中毕然会发现,RESTful接口在的功能体现出了天然的优势,不仅自述性强,操作、资源、表现形式解耦合,还利于缓存方便管理,但存在这样的问题,一个完整的Web系统,绝不可能只存在最简单的CRUD操作,除了前端可释义的基本操作(比如注册对应创建资源)外,还存在这多步资源操作,比如登录操作。登录基于查询功能,但它并不是简单的查询,而是查询带逻辑的业务,简单的查询接口向后台请求并不能得到用户登录状态的信息,因此对于此类接口,我们应额外抽象合理的方法请求,以登录为例:

GET http://localhost/session  //登录信息以ajax或表单传

我们将登录过后的过程抽象为一次用户会话,登录成功即标志会话的开始,那么注销该怎么表示?

DELETE http://localhost/session/3  

上述接口表示将3号用户注销,也就是删除3号用户的本次会话。

7.接口版本和完整表述

一个接口要不要加版本号?这个问题其实很简单,但也是一直在讨论的热门问题。我的回答是:根据软件的后期维护情况,考虑是否添加版本号。有两种情况——第一,我们作为乙方,只存在一次开发的义务,而甲方并没有后期版本迭代和维护的意向,此时我们可以考虑不添加版本信息;第二,一个正常的系统势必要经过长期的版本迭代,因此版本号是必要的。
如果我需要做版本迭代,但就是不想加版本号?
这个情况会造成C/S客户端运行异常,新版本用户正常使用软件,而老版本用户会因为没有更新客户端而导致功能出现异常甚至崩溃。
另外,一个完善的接口应该分功能模块,简单的接口不能保证接口冲突。例如,我们加上语义化版本和模块信息后的完整接口可以是这样的:

GET http://localhost/ver1.0.0/lightingshop/users

上述接口表示

  • 基于RESTful风格设计查询接口
  • 产品版本为1.0.0
  • 作用是向后端请求lightingshop模块的user表种所有用户信息

总结

RESTful设计已经成为Web应用设计的热门,无论是类似于前后端接口文档说明的软件Swagger还是风靡微服务领域的一站式解决方案SpringCloud,都采用的RESTful API的形式。无疑RESTful是一种十分简洁方便且益处良多的设计风格,顾名思义,放松地做接口设计,轻松的做开发。Why not have a try?
restful

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值