当前位置: 首页 > 科技观察

在你花5分钟看完这篇文章之前,你发现你根本不懂RESTful

时间:2023-03-15 22:07:00 科技观察

前言在学习RESTful风格的界面之前,即使你不知道它是什么,你一定很好奇它能解决什么问题?有哪些应用场景?听完下面的描述,我想你就明白了:在互联网还没有完全普及的早期,移动端还没有那么普及,页面请求和并发都不高。那时候人们对接口的要求还没有那么高。一些动态页面(jsp)可以满足绝大多数的使用需求。然而,随着互联网和移动设备的发展,人们对Web应用的需求也越来越大。传统的动态页面由于效率低下逐渐被HTML+JavaScript(Ajax)前端分离所取代,Android、IOS、小程序等客户端形式层出不穷,客户端类型呈现多样化,而客户端和服务器需要接口来进行通信,但是接口的标准化又成了一个问题:所以一套结构清晰、符合标准、易于理解、扩展方便的大多数人都能理解和使用的接口风格越来越重要接受,而RESTful风格的接口(RESTfulAPI)恰恰具有以上特点,并逐渐在实践中得到应用并得到普及。现在,RESTful是目前最流行的接口设计规范,在很多公司都有广泛的应用。其中Github的API设计是非常标准的RESTfulAPI,大家可以参考学习。在开发实践中,我们很多人可能还是会使用传统的API来进行请求交互。事实上,很多人对RESTfulAPI了解不多。他们对RESTfulAPI的理解可能停留在:面向资源是一种风格(误解)接口传递参数之间用斜杠(/)分隔,而不是问号(?)。其实一个很大的误区就是不要认为没有查询字符串就是RESTfulAPI,不要认为有查询字符串就不是RESTfulAPI,不要认为使用JSON传输的API就是RESTfulAPI.本文将带你了解RESTful,使用SpringBoot实践RESTfulAPI。一、REST介绍REST可能涉及到一些概念性的东西。在真正实战RESTfulAPI之前,必须对REST相关知识有一个系统的了解。REST的诞生REST(英文:RepresentationalStateTransfer,简称REST,直译为表现层状态转移)是一种软件架构风格和设计风格,不是标准,只是提供了一套设计原则和约束条件。主要用于客户端和服务器交互软件。基于这种风格设计的软件可以更简洁、更有层次感,也更容易实现缓存等机制。它最早出现在RoyThomasFielding2000年的博士论文中,定义并详述了RepresentationalStateTransfer(REST)的架构风格,并描述了如何使用REST来指导现代Web架构的设计和开发。用他自己的话说:我写这篇文章的目的是为了在符合架构原则的前提下,理解和评估基于网络的应用软件的架构设计,得到一个功能强、性能好、适用的架构沟通。需要注意的是,REST并没有明确的标准,更像是一种设计风格。我们把符合这种设计风格的程序或接口称为RESTful(字面意思是形容词)。所以RESTfulAPI是满足REST架构风格的接口。Fielding博士回答说,当时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):从服务器中删除一个资源。当然也有很多是在实际使用的时候用PUT来表示更新的。从请求过程来看,RESTfulAPI和传统API大致结构如下:URI指向资源:URI=UniversalResourceIdentifier,用于标识抽象或物理资源的紧凑字符串。URI包括URL和URN,这里更多的时候可能指的是URL(UniformResourceLocator)。RESTful是面向资源的,每一种资源都可能关联一个或多个URI,但一个URI只指向一个资源。无状态:服务器不能保存客户端的信息。从客户端发送的每个请求都必须包含所有必要的状态信息。会话信息由客户端保存,服务器根据这些状态信息处理请求。当客户端可以切换到新状态时发送请求信息。当发送一个或多个请求时,客户端处于状态转换过程中。每个应用程序的状态描述可以被客户端用来启动下一个状态转换。REST架构约束Fielding在他的论文中提出了REST架构的6大约束,也可以称为RESTful的6大原则。标准的REST约束应该满足以下6条原则:客户端-服务器(Client-Server):这个更注重客户端和服务端的分离,服务端的独立性可以更好的为前端、Android、IOS服务和其他客户端设备。无状态:服务端不保存客户端状态,客户端保存状态信息,每次请求都携带状态信息。可缓存性:服务端需要回复是否可以缓存,以便客户端识别缓存是否可以提高效率。统一接口:按照一定的原则设计接口,减少耦合,简化系统架构,是RESTful设计的基本出发点。当然,除了本篇内容提到的上述特性外,更详细的信息可以参考这篇REST论文的内容。分层系统:客户端无法直接知道自己连接的是终端还是中间设备。分层系统允许您灵活部署服务器端项目。Code-On-Demand(代码点播,optional):Code-On-Demand让我们可以灵活的向客户端发送一些看似特殊的代码,比如JavaScript代码。这里先介绍REST架构的一些风格和约束,后面会详细介绍RESTful风格的API。2.RESTfulAPI设计规范了解了RESTful的一些规则和特点之后,我们应该如何设计一个RESTfulAPI呢?我们应该详细考虑URL路径、HTTP请求动词、状态码和返回结果。至于其他方面如错误处理、过滤信息等规范,这里不再详细介绍。URL设计规范URL是一个统一的资源定位符,接口属于服务器端资源。您必须首先通过URL定位资源才能访问它。通常,一个完整的URL由以下几部分组成:URI=scheme"://"host":"port"/"path["?"query]["#"fragment]scheme:指底层协议,如http、https、ftphost:服务器的IP地址或域名port:端口,http默认为80portpath:访问资源的路径,即各种web框架中定义的route路由。query:查询字符串,是发送给服务器的参数。这里,发送了更多的数据分页、排序等参数。fragment:锚点,定位页面上的资源。我们在设计API时需要仔细考虑URL的路径,RESTful对路径的设计做了一些规范。通常RESTfulAPI的路径组成如下:/{version}/{resources}/{resource_id}version:API版本号。一些版本号也可以放在头信息中。控制版本号有利于应用迭代。resources:资源,RESTfulAPI推荐使用小写英文单词的复数形式。resource_id:资源的id,访问或操作资源。当然,有时资源层级可能很大,其下可以细分出很多子资源,URL路径可以灵活设计,例如:/{version}/{resources}/{resource_id}/{subresources}/{subresource_id}另外,有时候增删改查可能不满足业务需求,可以在url末尾添加action,例如/{version}/{resources}/{resource_id}/action其中action是对资源的操作。从大体上理解了URL路径的构成后,RESTfulAPI的URL具体设计规范如下:不使用大写字母,单词全部使用英文和小写。对于连字符,使用中斜线“-”代替下斜线“_”正确使用“/”表示层次关系,URL层级不宜太深,前层越高相对越稳定,结尾不应该包含正斜杠分隔符“/”URL中没有动词,使用请求方法表示动作资源,使用复数,不要使用单数,不要使用文件扩展名HTTPverbInRESTfulAPI,不同的HTTP请求方式有其各自的含义,这里分别对GET、POST、PUT、DELETE几种请求API进行设计及含义分析。对于不同的操作,具体含义如下:GET/collection:从服务器查询资源列表(数组)GET/collection/resource:从服务器查询单个资源POST/collection:在服务器上创建一个新资源PUT/collection/resource:更新服务器资源DELETE/collection/resource:从服务器删除资源在非RESTfulAPI中,我们通常使用GET请求和POST请求来完成增删改查等操作。查询和删除一般使用GET请求,更新和插入一般使用POST请求。从请求方法中,无法知道API是干什么的。所有的URL都会有操作动词来表示API执行的动作,例如:query,add,update,delete等。RESTful风格的API要求在URL上出现名词,想要的操作可以从几个请求方法,这与非RE??STful风格的API形成鲜明对比。说到GET、POST、PUT、DELETE,就不得不提到接口的安全性和幂等性,这里的安全性是指方法不会修改资源状态,即读操作是安全的,而写操作是不安全的。而幂等性是指一次操作和多次操作的最终效果是一样的,客户端多次调用只返回相同的结果。以上四种HTTP请求方式的安全性和幂等性如下:状态码和返回数据经过服务端处理后,客户端可能不知道是成功了还是失败了。服务器响应时,包含两个状态码和返回数据。部分。状态码我们首先要正确使用各种状态码来表示请求的处理和执行结果。状态码主要分为五类:1xx:相关信息2xx:运行成功3xx:重定向4xx:客户端错误5xx:服务端错误每个类别下都有几个子类,状态码的种类很多,主要常用的状态码如下所列:200OK-[GET]:服务器成功返回用户请求的数据,操作是幂等的(Idempotent)。201CREATED-[POST/PUT/PATCH]:??用户成功创建或修改数据。202Accepted-[*]:表示请求已在后台排队(异步任务)204NOCONTENT-[DELETE]:用户删除数据成功。400INVALIDREQUEST-[POST/PUT/PATCH]:??用户发送的请求有错误,服务器没有创建或修改数据。这个操作是幂等的。401Unauthorized-[*]:表示用户没有权限(token、用户名、密码错误)。403Forbidden-[*]表示用户已获得授权(与401错误相反),但访问被禁止。404NOTFOUND-[*]:用户发送的请求是针对一条不存在的记录,服务器没有进行任何操作,是幂等的。406NotAcceptable-[GET]:用户请求的格式不可用(比如用户请求JSON格式,但只请求XML格式)。410Gone-[GET]:用户请求的资源被永久删除,不会再次获取。422无法处理的实体-[POST/PUT/PATCH]创建对象时发生验证错误。500INTERNALSERVERERROR-[*]:服务器发生错误,用户将无法确定请求是否成功。返回结果基于不同的操作。服务端返回数据给用户,每个团队或者公司封装的返回的实体类也不一样,但是都是返回JSON格式的数据给客户端。第三层是RESTfulAPI案例。上面讲了RESTful的理论知识。来实现一个小案例吧!在本案例的实战中,我们访问的RESTful接口才是对数据库的真正操作,创建新数据库,创建数据库和表(根据自己的喜好)。选择Maven依赖时,只需要勾选SpringWeb模块、MySQL驱动、MyBatis框架即可。本例中的POJO创建了一个Dog.java实体对象,其具体结构为:packagecom.restfuldemo.pojo;publicclassDog{privateintid;//唯一id标识privateStringname;//nameprivateintage;//age//getsetomitted}上面创建的项目,我们开始构建RESTful风格的API。在构建RESTfulAPI时,需要对各种请求有更详细的了解。当然,本案例在实现各种请求时,为了方便演示,并没有完全遵循RESTfulAPI规范。比如版本号等信息这里就不加了,案例更侧重于使用SpringBoot实现这个接口。本案例实现了狗狗资源的增删改查。non-RESTful和RESTful接口的对比如下:另外,使用postman发送请求时,传给后端常用的文件类型有3种:form-data:是表单中的multipartform/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方式向后端传值。GETPOSTPUTDELETE请求GET请求用于获取资源:GET请求会向数据库发送一个数据请求来获取资源,这个请求就像数据库的select操作一样,只是用来查询数据,不会影响资源的内容。不管你做了多少次,结果都是一样的。而GET请求会将请求的参数追加到URL中,但不同的浏览器对其大小和长度的限制不同。本例中,我们设计了两个GET请求API。GET/dogs:用于返回狗资源列表。GET/dogs/{dogid}:用于查询此id的单个狗资源。POST请求用于添加新资源:POST请求向服务器发送数据,但是请求会改变数据的内容(新增),就像数据库的插入操作一样,会创建新的内容。而POST请求的请求参数都在请求体中,其大小没有限制。在这种情况下,我们为以下POST请求设计API。POST/dogs:在服务器上添加狗资源。PUT请求用于更新资源。PUT请求是向服务器发送数据。与POST请求不同,PUT请求侧重于数据的修改,就像数据库中的更新一样,而POST请求侧重于数据的增加。在这种情况下,我们为以下POST请求设计API。PUT/dogs/{dogid}:用于使用此id更新单个狗资源。DELETE请求是用来删除资源的,DELETE请求的目的和它的字面意思是一致的,就是用来删除资源的。对应于数据库中的删除。在这种情况下,我们为DELETE请求设计了以下API。DELETE/dogs/{dogid}:用于删除具有此id的单个狗资源。对应的Mapper文件为:packagecom.restfuldemo.mapper;importcom.restfuldemo.pojo.Dog;importorg.apache.ibatis.annotations.*;importjava.util.List;@MapperpublicinterfaceDogMapper{@Select("select*fromdog")ListgetAllDog();@Select("select*fromdogwhereid=#{id}")DoggetDogById(@Param("id")intid);@Insert("insertintodog(name,age)values(#{name},#{age})")booleanaddDog(Dogdog);@Update("updatedogsetname=#{name},age=#{age}whereid=#{id}")booleanupdateDog(Dogdog);@Delete("deletefromdogwhereid=#{id}")booleandeleteDogById(intid);}对应控制器文件为:packagecom.restfuldemo.controller;importcom.restfuldemo.mapper.DogMapper;importcom.restfuldemo.pojo.Dog;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.*;importjava.util.Arrays;importjava.util.List;@RestControllerpublicclassTestController{@Autowired(required=false)DogMapperdogMapper;@GetMapping("dogs")publicListgetDogs(){returndogMapper.getAllDog();}@GetMapping("dogs/{id}")publicDoggetDogById(@PathVariable("id")intid){Dogdog=dogMapper.getDogById(id);returndog;}@PostMapping("dogs")publicbooleanaddDog(Dogdog){returndogMapper.addDog(dog);}@PutMapping("dogs/{id}")publicbooleanupdateDog(@PathVariable("id")intid,@RequestParam("名称")Stringname,@RequestParam("age")intage){Dogdog=dogMapper.getDogById(id);dog.setName(name);dog.setAge(age);returndogMapper.updateDog(dog);}@DeleteMapping("dogs/{id}")publicbooleandeleteDog(@PathVariable("id")intid){returndogMapper.deleteDogById(id);}}经笔者测试,一切正常。总结RESTful风格的API很好很规范,但是网上大部分公司并没有按照或者完全按照它的规则来设计,因为REST是一种风格,而不是一种约束或者规则,过于理想的RESTfulAPI会付出太多代价很多成本。例如,RESTfulAPI也有一些缺点,比如操作方法繁琐。RESTfulAPI通常按照GET、POST、PUT、DELETE来区分操作资源的动作,而HTTPMethod本身是不直接可见的,是隐藏的,如果动作放在URL的路径中则相反,清晰可见,更有利于团队理解和沟通。而且有些浏览器对GET和POST以外的请求不是很友好,需要特殊的额外处理。过分强调资源,实际业务API可能有各种更复杂的需求。仅靠资源的增删改查可能无法有效满足使用需求。强行使用RESTful风格的API只会增加开发的难度和成本。所以,当你或者你的技术团队在设计API的时候,如果使用场景符合REST风格,那么就可以采用RESTful风格的API。但是,如果业务需求和RESTful风格的API不匹配或者很麻烦,那么可以使用RESTful风格的API或者借鉴。毕竟无论哪种风格的API,都是为了方便团队开发、协商和管理,不能墨守成规。至此,RESTfulAPI的介绍和实战就结束了。本文先介绍RESTful的一些特点,然后进入SpringBoot对RESTfulAPI的实战。最后,也说说RESTfulAPI的一些不完善之处。我相信你聪明睿智。有着非常深刻的理解。肯定会在以后项目的API设计中进行优化。不同的人可能对RESTfulAPI有不同的理解,但存在是合理的。RESTfulAPI有其鲜明的优势和特点,是目前主要的API设计类型之一,所以掌握和理解RESTfulAPI还是很重要的!