Json就是RESTful吗?
===============
上一篇介绍了Get和Post的本质区别,但是感觉还不能算完。
因为谈到HTTP,不得不提一下大名鼎鼎的RESTful。印象中有些同学认为使用Json就是RESTful的,这是完全错误的。
RESTful,全称是Representational State Transfer,中文的意思是表现层状态转移(很拗口,下面会再解释),它不是一种技术或协议,而是一种软件架构风格(软件系统组织方式的模式)。这种架构风格是由Roy Fielding在他2000年的博士论文中提出的,Roy Fielding是HTTP协议的主要设计者之一,他在论文中介绍了REST这一概念,用来指导网络架构的设计原则。
在RESTful被提出之前,Web服务主要基于SOAP(一种XML协议,微软的WCF是其中的佼佼者),这种方式虽然功能强大,但也相对复杂,学习SOAP需要掌握XML语法、理解复杂的WSDL(Web Services Description Language)文档,以及熟悉SOAP消息的生成、解析和处理机制,严格的定义和复杂的规范,对开发者而言有比较高的学习门槛。
RESTful架构则充分利用了HTTP本身的特性,是一种简单、高效的网络服务设计方式。
与HTTP的关系
RESTful架构是由HTTP协议的主要设计者提出的,其与HTTP协议有一种天然的契合。RESTful架构可以通过使用HTTP协议的方法来实现资源的操作,这可以让RESTful更易于理解和实现。
HTTP本身就是一个无状态的协议,RESTful也是基于无状态性来设计的。HTTP定义了一系列的方法(如GET、POST、PUT、DELETE等),这些方法可以对应到RESTful架构中对资源的基本操作:获取(GET)、创建(POST)、更新(PUT)和删除(DELETE)。
RESTful API并非严格限定只能使用HTTP协议来实现,但在现实世界中,由于HTTP在互联网上的普及程度、标准支持的完善性以及与Web架构的深度整合,HTTP就是实现RESTful API的标准选择。
基本用法
让我们通过一个例子来看看RESTful的基本使用姿势:
假设我们正在开发一个博客系统,我们可以定义如下的RESTful API:
- 获取所有博客列表:GET /blogs
- 创建新的博客:POST /blogs
- 获取指定ID的博客详情:GET /blogs/{id}
- 更新指定ID的博客:PUT /blogs/{id}
- 删除指定ID的博客:DELETE /blogs/{id}
在这个例子中,我们操作的资源是博客(blog),用到了HTTP的GET、POST、PUT、DELETE等多种方法,实现了对资源的查、增、改、删。
可以看出,RESTful架构充分利用了HTTP协议的特性,设计和实现了一种高效、清晰的网络服务开发方法。
如何理解表现层状态转移
为什么要使用“表现层状态转移”这么拗口的名字?
首先我们要理解RESTful是围绕“资源”来设计的,在RESTful架构中,一切皆为资源。资源是任何可以被命名、唯一标识并在网络上访问的事物。例如,博客文章、用户账户、订单、照片等都是资源。每个资源都有一个唯一的资源标识符(URI,Uniform Resource Identifier),如/users/123、/articles/happy-birthday等,它们可以在网络中被定位和访问。
然后我们分别理解下这三个关键词:表现层、状态和转移。
表现层(Representational)
表现层指的是资源的表现形式,也就是数据的结构化组织方式,比如XML、JSON、HTML等。之所以有这么多种表现形式,是因为不同的客户端可能需要不同的资源表现形式。服务端可以根据客户端指定的形式返回表现层,比如在HTTP Header中使用Accept来指定返回XML还是JSON格式。
我们可以用一个很形象的比喻来理解,你去餐馆点菜,菜品(资源)可以有多种做法(表现形式),比如红烧、清蒸等,食客可以根据自己的喜好(需求)选择。
状态(State)
状态指的是某一时刻资源(数据)的状态,或者说是数据的当前状况。就像你点的那盘菜,它可能是新鲜的、也可能是已经凉了的,这就是菜品的“状态”。
转移(Transfer)
转移,是指在客户端和服务端的交互过程中,资源状态的变化。
在RESTful架构中,这通过HTTP的GET、POST、PUT、DELETE等方法实现。每当我们使用这些HTTP方法操作资源时,资源的状态就可能发生改变。比如,使用GET方法可以查看菜品信息(不改变状态),使用POST方法可能就是下单这道菜(改变了资源的状态,从“可订”变为“已订”)。
将这三个概念综合起来,”表现层状态转移”就是通过HTTP协议在客户端和服务端之间传输资源的表现形式,从而实现资源状态的变化和管理。
还是用点餐来加强理解,我们通过美团外卖点餐,在APP上看到菜品的图片和描述(表现层),然后选择了某个菜品加入购物车并下单(状态),通过网络将我们的订单(状态)发送给餐馆(转移)。餐馆接到订单后,开始加热你的预制菜(😢),这个过程就是一次“表现层状态转移”的实践。
应用RESTful的挑战
RESTful本身的缺点
状态管理:REST是无状态的,客户端每次请求服务端时都需要携带这次交互需要的所有信息,因此所有的状态实际都是在客户端管理的。这种设计虽然简化了服务器的设计、提高了系统的可伸缩性,但同时也把状态管理的责任转移到了客户端,可能导致客户端逻辑变得复杂。
比如在电商的购物车应用中,如果用户添加商品、修改数量、删除商品等操作都必须由客户端在每次请求中包含完整的购物车状态,那么客户端就需要负责维护购物车的完整状态,这会让客户端逻辑变得有点复杂:
- 状态同步:客户端需要确保自己的状态与服务器上的状态一致,特别是在多设备登录的情况下,状态同步会变得更加复杂。
- 事务性操作:在一些需要事务性保障的场景下,如结算过程中需要同时计算价格、生成订单、更新库存等,客户端需要以某种方式确保这些操作的原子性,这在无状态的REST架构中是一个挑战。
- 错误处理:由于所有的状态都在客户端维护,因此任何网络中断或请求失败都需要客户端来处理,并确保状态的一致性。
当然我们也可以通过适当的技术手段解决这些问题,比如使用Session、服务端提供一些事务型接口,在保持REST原则精神的同时,平衡客户端与服务器之间的状态管理责任。
过度获取/不足获取数据:RESTful API通常以资源为中心,有时候一个客户端的请求可能只需要资源的一小部分数据,但却不得不获取整个资源的表示,这会导致数据传输的浪费。相反,如果需要聚合多个资源的数据,可能需要发起多次请求,增加了客户端的复杂性和响应时间。
当然这也是有解的,GraphQL的出现就是为了解决这个问题的。
版本控制:随着业务的发展,RESTful API可能需要进行版本更新。常见的API版本控制策略有通过URI路径、查询参数、自定义请求头、或者通过内容协商等方式,但是会面临一些困难:
- URI路径(如/api/v1/resource)违反了REST原则中对URL的最佳实践指导;
- 查询参数(如/api/resource?version=1)则会让版本控制逻辑分散在程序的多个地方,难以维护;
- 自定义请求头(如Accept: application/vnd.example.v1+json)虽然符合REST原则,但对客户端来说不够直观,需要读文档;
- 内容协商 利用HTTP的Accept和Content-Type头部进行版本控制,优雅但实现复杂。
还有版本向后兼容的问题,文档更新和沟通的问题,都是不小的挑战。需要保持系统的灵活性,但是不能把事情搞得太复杂了。当然其中某些挑战是一些通用的问题,只是RESTful可能会带来更多的限制。
统一的接口约束:RESTful架构要求API具有统一的接口,也就是对资源的增(POST)、删(DELETE)、改(PUT)、查(GET)这一套,但是这在多样化的业务需求下可能限制了API设计的灵活性。还是以电商系统的结算为例,在RESTful架构下,需要对“订单”、“库存”、“账户”、“积分”等资源分别进行操作,这些操作是紧密关联的,分开处理会显得繁琐,增加客户端的请求次数和复杂度,还难以保持事务性。
要解决这个问题,还是要回归到实用主义,采用一些折衷的方法,比如对于涉及多个资源或复杂逻辑的操作,可以设计自定义的复合操作接口。
开发者的适应性
虽然RESTful这个架构风格已经提出来20多年了,但是对于写惯了过程式开发的同学还是有很大的转变困难,很多号称RESTful的API只是形式上看着像,使用了HTTP方法、使用了JSON数据格式,但是其实还是过程式的思维。
这里的过程式开发主要说的是RPC,也就是远程过程调用。我们看一下RPC和RESTful的一些重要区别:
- 设计理念:RPC更侧重于行为(调用远程的过程或方法),而RESTful强调的是资源(网络上的实体和对这些实体的操作)。如何识别出正确的资源概念,这需要一定的学习和适应过程,比如登录操作对应的是创建一个新的会话资源,这个思维不容易转变。
- 接口风格:RPC的接口通常是按照功能来组织的,比如addUser()、deleteUser()等;而RESTful则是以资源为中心,通过HTTP方法(GET、POST、PUT、DELETE等)来实现对user资源的操作。开发者需要学习如何使用URI来表示资源,以及如何通过HTTP方法来表达对资源的操作。
- 数据传输格式:RPC可以支持多种数据传输格式(如JSON、XML、二进制等),而RESTful通常使用HTTP标准支持的格式,如JSON和XML。
- 状态管理:RPC通常是有状态的,而RESTful架构则是无状态的,这意味着每次请求都需要包含所有必要的信息,服务器不会保存之前的任何请求状态。
思维上的转变是比较困难的,特别是遇到RESTful不能很好的解决问题时,比如无状态带来的复杂的客户端逻辑、面向资源导致的性能开销等,开发者往往会出现抵触,这也是很多API不伦不类的主要原因。
这需要一定的学习和适应过程,最好还要有权威且专业的意见来进行引导,否则很难在业务压力和惯性思维的作用下坚持下去。
关注萤火架构,提升技术认知!
原文链接: https://juejin.cn/post/7352075810935357449
文章收集整理于网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除,如若转载,请注明出处:http://www.cxyroad.com/17944.html