在学习RESTful 风格接口以前,即便你不知道它是什么,但你确定会好奇它能解决什么问题?有什么应用场景?听完下面描述我想你就会明白:前端
在互联网并无彻底流行的初期,移动端也没有那么盛行,页面请求和并发量也不高,那时候人们对接口的要求没那么高,一些动态页面(jsp)就能知足绝大多数的使用需求。java
可是随着互联网和移动设备的发展,人们对Web应用的使用需求也增长,传统的动态页面因为低效率而渐渐被HTML+JavaScript(Ajax)的先后端分离所取代,而且安卓、IOS、小程序等形式客户端层出不穷,客户端的种类出现多元化,而客户端和服务端就须要接口进行通讯,但接口的规范性就又成了一个问题:git
因此一套结构清晰、符合标准、易于理解、扩展方便让大部分人都可以理解接受的接口风格就显得愈来愈重要,而RESTful风格的接口(RESTful API)恰好有以上特色,就逐渐被实践应用而变得流行起来。github
如今,RESTful是目前最流行的接口设计规范,在不少公司有着普遍的应用,其中Github 的API设计就是很标准的RESTful API,你能够参考学习。web
在开发实践中咱们不少人可能仍是使用传统API进行请求交互,不少人其实并不特别了解RESTful API,对RESTful API的认知可能会停留在:spring
而其实一个很大的误区不要认为没有查询字符串就是RESTful API,也不要认为用了查询字符串就不是RESTful API,更不要认为用了JSON传输的API就是RESTful API。数据库
本教程将带你了解RESTful并用SpringBoot实战RESTful API,在实现本案例前,你须要保证你的电脑上apache
REST涉及一些概念性的东西可能比较多,在实战RESTful API以前,要对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和RESTful的联系和区别,如今就要开始好好了解RESTful的一些约束条件和规则,RESTful是一种风格而不是标准,而这个风格大体有如下几个主要特征:
以资源为基础 :资源能够是一个图片、音乐、一个XML格式、HTML格式或者JSON格式等网络上的一个实体,除了一些二进制的资源外普通的文本资源更多以JSON为载体、面向用户的一组数据(一般从数据库中查询而获得)。
统一接口: 对资源的操做包括获取、建立、修改和删除,这些操做正好对应HTTP协议提供的GET、POST、PUT和DELETE方法。换言而知,使用RESTful风格的接口但从接口上你可能只能定位其资源,可是没法知晓它具体进行了什么操做,须要具体了解其发生了什么操做动做要从其HTTP请求方法类型上进行判断。具体的HTTP方法和方法含义以下:
固然也有不少在具体使用的时候使用PUT表示更新。从请求的流程来看,RESTful API和传统API大体架构以下:
URI指向资源:URI = Universal Resource Identifier 统一资源标志符,用来标识抽象或物理资源的一个紧凑字符串。URI包括URL和URN,在这里更多时候可能代指URL(统一资源定位符)。RESTful是面向资源的,每种资源可能由一个或多个URI对应,但一个URI只指向一种资源。
无状态:服务器不能保存客户端的信息, 每一次从客户端发送的请求中,要包含全部必须的状态信息,会话信息由客户端保存, 服务器端根据这些状态信息来处理请求。 当客户端能够切换到一个新状态的时候发送请求信息, 当一个或者多个请求被发送以后, 客户端就处于一个状态变迁过程当中。 每个应用的状态描述能够被客户端用来初始化下一次的状态变迁。
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的一些规则和特性,那么具体该怎么去设计一个RESTful API呢?要从URL路径、HTTP请求动词、状态码和返回结果等方面详细考虑。至于其余的方面例如错误处理、过滤信息等规范这里就不详细介绍了。
URL为统一资源定位器 ,接口属于服务端资源,首先要经过URL这个定位到资源才能去访问,而一般一个完整的URL组成由如下几个部分构成:
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组成以下:
/{version}/{resources}/{resource_id}
version:API版本号,有些版本号放置在头信息中也能够,经过控制版本号有利于应用迭代。
resources:资源,RESTful API推荐用小写英文单词的复数形式。
resource_id:资源的id,访问或操做该资源。
固然,有时候可能资源级别较大,其下还可细分不少子资源也能够灵活设计URL的path,例如:
/{version}/{resources}/{resource_id}/{subresources}/{subresource_id}
此外,有时可能增删改查没法知足业务要求,能够在URL末尾加上action,例如
/{version}/{resources}/{resource_id}/action
其中action就是对资源的操做。
从大致样式了解URL路径组成以后,对于RESTful API的URL具体设计的规范以下:
"-"
而不用下杠"_"
"/"
表示层级关系,URL的层级不要过深,而且越靠前的层级应该相对越稳定"/"
在RESTful API中,不一样的HTTP请求方法有各自的含义,这里就展现GET,POST,PUT,DELETE几种请求API的设计与含义分析。针对不一样操做,具体的含义以下:
GET /collection:从服务器查询资源的列表(数组)GET /collection/resource:从服务器查询单个资源POST /collection:在服务器建立新的资源PUT /collection/resource:更新服务器资源DELETE /collection/resource:从服务器删除资源
在非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理论知识,下面动手实现一个小案例吧!
在本案例的实战中,咱们访问的RESTful接口都是对数据库真实的操做,新建数据库,建立一个数据库和表(根据本身喜爱)。
选择Maven依赖的时候,只须要勾选其中Spring的Web模块、MySQL驱动以及MyBatis框架。
本案例的POJO建立Dog.java实体对象,其具体构造为:
package com.restfuldemo.pojo;public class Dog { private int id;//惟一id标识 private String name;//名称 private int age;//年龄 //省略get set}
上面建立好了项目,咱们就开始构建RESTful风格的API。在具体构建RESTful API的时候,须要对各类请求有更细致的认知,固然,本案例在实现各类请求的时候为了演示的便捷并无彻底遵循RESTful API规范,例如版本号等信息这里就不添加了,案例更侧重于使用SpringBoot实现这个接口。
本案例实现对dog资源的增删改查,以下是非RESTful 和RESTful接口对比:
API name | 非 RESTful | RESTful |
---|---|---|
获取dog | /dogs/query/{dogid} |
GET: /dogs/{dogid } |
插入dog | /dogs/add |
POST: /dogs |
更新dog | /dogs/update/{dogid} |
PUT:/dogs/{dogid} |
删除dog | /dods/delete/{dogid} |
DELETE:/dogs/{dogid} |
另外在使用postman进行发送请求的时候,有三种经常使用的文件类型传递到后端:
form-data : 就是form表单中的multipart/form-data,会将表单数据处理为一条信息,用特定标签符将一条条信息分割开,而这个文件类型一般用来上传二进制文件。
x-www-form-urlencoded:就是application/x-www-form-urlencoded,是form表单默认的encType,form表单会将表单内的数据转换为键值对,这种格式不能上传文件。
raw:能够上传任意格式的文本,能够上传Text,JSON,XML等,但目前大部分仍是上传JSON格式数据。当后端须要接收JSON格式数据处理的时候,能够采用这种格式来测试。
由于GET请求查询参数在URL上,其余类型请求使用x-www-form-urlencoded方式向后端传值。
GET请求用来获取资源:GET请求会向数据库发索取数据的请求,从而来获取资源,该请求就像数据库的select操做同样,只是用来查询数据,不会影响资源的内容。不管进行多少次操做,结果都是同样的。
而且GET请求会把请求的参数附加在URL后面,可是不一样的浏览器对其有不一样的大小长度限制。
在本案例中,咱们设计两个GET请求的API。GET /dogs
:用来返回dog资源的列表。GET /dogs/{dogid}
:用来查询此id的单个dog资源。
POST请求用来新增一个资源 : POST请求向服务器发送数据,可是该请求会改变数据的内容(新添),就像数据库的insert
操做同样,会建立新的内容。且POST请求的请求参数都是请求体中,其大小是没有限制的。
在本案例中,咱们设计如下POST请求的API。POST /dogs
:服务端新增一个dog资源。
PUT请求用来更新资源,PUT请求是向服务器端发送数据的, 与POST请求不一样的是,PUT请求侧重于数据的修改 ,就像数据库中update同样,而POST请求侧重于数据的增长。
在本案例中,咱们设计如下POST请求的API。PUT /dogs/{dogid}
:用来更新此id的单个dog资源。
DELETE 请求用来删除资源,DELETE请求用途和它字面意思一致,用来删除资源。和数据库中delete相对应。
在本案例中,咱们设计如下DELETE请求的API。DELETE /dogs/{dogid}
:用来删除此id的单个dog资源。
对应的Mapper文件为:
package com.restfuldemo.mapper;import com.restfuldemo.pojo.Dog;import org.apache.ibatis.annotations.*;import java.util.List;@Mapperpublic interface DogMapper { @Select("select * from dog") List<Dog> getAllDog(); @Select("select * from dog where id=#{id}") Dog getDogById(@Param("id") int id); @Insert("insert into dog (name,age) values (#{name},#{age})") boolean addDog(Dog dog); @Update("update dog set name=#{name},age=#{age} where id=#{id}") boolean updateDog(Dog dog); @Delete("delete from dog where id=#{id}") boolean deleteDogById(int id); }
对应controller文件为:
package com.restfuldemo.controller;import com.restfuldemo.mapper.DogMapper;import com.restfuldemo.pojo.Dog;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import java.util.Arrays;import java.util.List;@RestControllerpublic class TestController { @Autowired(required = false) DogMapper dogMapper; @GetMapping("dogs") public List<Dog> getDogs() { return dogMapper.getAllDog(); } @GetMapping("dogs/{id}") public Dog getDogById(@PathVariable("id") int id) { Dog dog=dogMapper.getDogById(id); return dog; } @PostMapping("dogs") public boolean addDog(Dog dog) { return dogMapper.addDog(dog); } @PutMapping("dogs/{id}") public boolean updateDog(@PathVariable("id")int id,@RequestParam("name")String name,@RequestParam("age")int age) { Dog dog=dogMapper.getDogById(id); dog.setName(name); dog.setAge(age); return dogMapper.updateDog(dog); } @DeleteMapping("dogs/{id}") public boolean deleteDog(@PathVariable("id") int id) { return dogMapper.deleteDogById(id); } }
通过笔者测试一切都是ok的,若是要项目源文件请联系笔者发你哈!
RESTful风格的API 当然很好很规范,但大多数互联网公司并无按照或者彻底按照其规则来设计,由于REST是一种风格,而不是一种约束或规则,过于理想的RESTful API 会付出太多的成本。
好比RESTful API也有一些缺点
因此,当你或大家的技术团队在设计API的时候,若是使用场景和REST风格很匹配,那么大家能够采用RESTful 风格API。可是若是业务需求和RESTful风格API不太匹配或者很麻烦,那也能够不用RESTful风格API或者能够借鉴一下,毕竟不管那种风格的API都是为了方便团队开发、协商以及管理,不能墨守成规。
到这里RESTful API的介绍和实战就结束啦,本篇首先从RESTful的一些特色进行介绍,再到SpringBoot实战RESTful API,最后也说了一些RESTful API并不完美的地方,相信睿智的你对RESTful 必定有了很深入的理解。在之后项目的API设计上定能有所优化。
不一样的人对RESTful API可能有着不一样的理解,但存在即合理,RESTful API有着其鲜明的优点和特色,目前也是一种API设计的主要选型之一,因此掌握和理解RESTful API仍是至关重要的!