本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!
背景介绍
在微服务架构的演进过程中,我们不难发现,服务间的调用方式正悄然发生变革,逐渐从传统的RPC调用向HTTP调用过渡。在日常工作中,时常听闻同事提及为其他系统提供微服务并暴露Restful接口。然而,对于许多初学者来说,RESTful接口这一概念仍显得模糊,其与REST的关系更是令人费解。
问题分析
为了深化大家对Rest和Restful架构的理解,我们精心策划了一系列问题,旨在为大家提供一个更具针对性和目的性的学习路径,希望这些问题能够引导您更有效地探索本篇文章的精髓。
Rest
Rest,本质上是一种架构范式,而非某种特定的协议。它更像是一座灯塔,为构建稳健系统的航行者指明方向。
随着Web技术的不断发展,REST架构已经成为了构建分布式系统的一种主流方式。它以其简洁、清晰和可扩展的特性,赢得了广大开发者的青睐。通过REST,我们可以更加灵活地设计系统,实现客户端和服务器之间的松耦合,提高系统的可维护性和可扩展性。
Rest定义
Rest,其全称是Representational State Transfer ,我们可以将其视为"资源状态转换"。在分布式系统的设计中,Rest以其独特的架构方法占据了一席之地,这一理念的开创者Roy Fielding,在博士论文中首次提出了这一思想。
Rest协议
Rest一种关于如何构建高效、可靠、可扩展的分布式系统的思考方式,它鼓励我们关注资源的状态变化,并通过HTTP等协议进行状态转换。这种转换过程中,资源的表征(如JSON、XML等格式)扮演着重要角色,使得客户端和服务器之间的通信变得清晰和高效。
Rest和Restful API
在了解了REST之后,我们自然会进一步思考:REST与RESTful API之间究竟有何种千丝万缕的联系?为了解答这个问题,我们首先要明确API的定义以及Restful API的内涵。
API
API,即应用程序接口,它充当着不同软件组件间交互的桥梁,使得各种服务能够无缝连接,实现数据的共享与功能的集成。作为服务与服务之间、客户端与服务端之间沟通的桥梁,扮演着至关重要的角色。 通过API的调用,能够便捷地从服务器获取所需的资源信息。当我们谈及RESTful API时,我们实际上是指那些严格遵循REST架构原则的API。
Restful API
Restful API,则是基于Rest(Representational State Transfer,表述性状态转移)架构风格设计的API,它强调资源的内容、状态的转移以及客户端与服务端之间的无状态通信。其设计原则使得网络服务更加简洁、清晰和易于理解,从而提升了网络应用的交互性和可维护性。
注意,并非所有采用HTTP协议的API都可以被称作RESTful API。这一称谓的前提是,你的系统必须是基于REST架构构建的。只有符合REST架构理念的API,才能真正称之为RESTful API。因此,RESTful API不仅是一个技术标签,更是对系统设计和实现方式的一种认可和肯定。
Restful API特点和优势
Restful API具有6大核心特质,它们共同构筑Rest架构的精髓与优势。让我们一同深入剖析这些特质,以便全面地认识Rest架构的魅力所在。
统一资源标识符(Uniform interface)
Restful系统高度重视资源的明确标识与便捷访问,每一个资源都享有其独一无二的URI(统一资源标识符),这确保了资源在系统中的可寻址性和可访问性。
在上图中的每一个服务端内部的小方块无疑是最为关键的元素。我们将资源视作一个个独立的实体,并为它们分配了独特的URI。这种设计使得每一个资源都能通过一个独立且唯一的URI进行表示,从而实现了资源的精确定位与高效访问。
Restful请求处理
通过URI,我们可以轻松地识别、定位和操作资源,无论是进行数据的读取、更新还是删除等操作,都能通过相应的URI来完成。这种设计方式使得Restful系统能够更加灵活地应对各种业务场景,为用户提供更加便捷、高效的服务。 单个的资源不能太大也不能太小,它表示的是一个独立的可以操作的单位。这些资源通过通用的获取方式来进行获取和操作。比如对资源的CURD可以分别用不同的HTTP method来表示(PUT,POST,GET,DELETE)。
Restful资源操作
在REST架构中,PUT、POST、GET和DELETE是四种常见的HTTP方法,它们各自具有特定的使用含义和适用场景,同时需要对资源进行统一的命名,定义统一的link格式和数据格式。
PUT方法
PUT方法用于更新资源,它是幂等的,即多次执行PUT操作具有相同的效果。
当需要完全替换或更新某个资源时,可以使用PUT方法。例如,在更新用户信息时,可以使用PUT方法将新的用户信息发送到服务器,服务器将用新的信息替换原有的用户资源。
POST方法
POST方法用于创建新的资源,它是非幂等的,即多次执行POST操作将导致多个资源的创建。
当需要在服务器上创建新的资源时,可以使用POST方法。例如,在创建新用户时,可以使用POST方法将用户信息发送到服务器,服务器将根据这些信息创建新的用户资源。此外,POST方法也可以用于提交表单数据或上传文件等操作。
GET方法
GET方法用于从服务器获取资源,它是安全的和幂等的,即无论执行多少次GET操作,都不会对资源造成任何影响,结果始终相同。
当需要从服务器获取数据时,可以使用GET方法。例如,在查询用户列表或获取文章详情时,可以通过GET方法发送请求到服务器,服务器将返回相应的资源数据。
DELETE方法
DELETE方法用于删除资源,它也是安全的和幂等的,即无论执行多少次DELETE操作,结果都是相同的,即删除指定的资源。
当需要删除服务器上的某个资源时,可以使用DELETE方法。例如,在删除用户或文章时,可以使用DELETE方法发送请求到服务器,服务器将删除指定的用户或文章资源。
客户端/服务端职责分离
在上面已经提到了,在Restful服务中,客户端与服务器端各自独立运行,职责分离,相互之间的唯一桥梁便是通过API进行交互。
- 客户端:无需深入了解服务器端的实现细节,只需通过API调用获取所需的资源。
- 服务端:无需关注客户端如何使用这些API,只需保证接口的稳定性和可用性。
这一原则在当前众多前后端分离的架构中得到了广泛应用,实现了客户端与服务器端的解耦,提高了系统的灵活性和可维护性。
无状态化处理
在Restful服务中,API调用与HTTP协议一样,均遵循无状态原则。这意味着服务器在处理请求时,不会保留API调用的历史记录,也不会存储任何关于客户端的特定信息。从服务器的视角来看,每个请求都是全新且独立的。 因此,用户的状态信息被设计为在客户端进行管理和维护。为了确保服务器能够准确识别并认证用户,客户端在发起每个接口请求时,都需要携带能够唯一标识用户的标记。
可缓存的资源
缓存作为提升系统性能的关键手段,在Restful服务中同样发挥着不可或缺的作用。对于Rest中的可缓存资源,明确标识其可缓存性至关重要。 通过这一标识,相关的调用方能够将这些资源进行有效缓存,进而显著提高系统的运行效率,这种缓存机制不仅减少了不必要的网络请求,还降低了服务器的负载压力,从而为用户带来更加流畅和高效的体验。
分层架构模式
在现今的系统中,分层设计已成为一种普遍实践,Restful服务亦不例外。只要确保对外提供的资源URI保持一致性,架构本身并不局限于特定层数的构建方式。
编码和解码
在Restful服务中,各个服务间的交互通常依赖于JSON或XML这类数据格式。在数据传输的过程中,为确保数据的完整性和安全性,客户端与服务端均须精心设计编码与解码操作。这一环节至关重要,它不仅能够保证数据在传输过程中的准确性,还能有效抵御潜在的安全威胁,为整个通信过程提供坚实的保障。 通过这一设计,我们能够构建一个更加稳健、安全的数据传输环境,提升系统的整体性能与可靠性。
Restful API获取资源
Restful服务中,资源的地位举足轻重,其核心理念与运作机制皆围绕资源展开。那么,究竟何为资源?如何为其命名并作出精准定义?接下来,让我们共同探寻这其中的奥秘。
资源的定义
资源是信息的载体,是对信息的核心抽象。在Rest的语境中,任何具有明确命名并承载信息的实体,无论是具体的对象、文档、图像,还是抽象的实体集合、服务等,均可被视作资源。此外,资源是和状态相关的,任何一个特定时间点的资源都有属于自己的资源状态。这些状态是由数据、描述数据的元数据和超媒体链接组成。
资源命名规则
在命名资源时,我们推荐遵循一套总体的规范:尽量使用小写字母,以确保命名的统一性和可读性。
层级关系规则
在Restful服务中,我们采用/
这一符号来清晰地展现资源之间的层级关系。举例来说,通过特定的路径组合,我们能够精确地定位到所需的资源,从而实现对资源的有效管理和操作。
shell
/第一层级/第二层级/第三层次/......
例如:
shell
// 获取国家基本信息,根据国家名称
/country/{countryName}
// 获取国家基本信息,查询对应省的基本信息,基于省的名称
/country/province/{provinceName}
// 当然如果出现了不同国家之间有相同的省,则可以加入国家的名称作为精确定位,如下所示
/country/{cityName}/province/{provinceName}
/country/province/{cityName}{provinceName}
注意,不要在资源的最后加上/,如
/country/province/{cityName}{provinceName}/
,不是特别符合Rest的定义规范和说明。
分隔符-
为了更精细地划分和命名资源,我们可以采用-
分隔符来进行资源路径的细化,不要使用下划线 。
举例来说,原本的/country/province/{cityName}{provinceName}
路径可以优化为/country-province-city/{cityName}
,这种写法不仅更为简洁,还增强了路径的可读性。
不同数据量操作
在Restful架构中,任何具备命名条件的信息均可被视为资源,它们既可以指代单一的个体,也可以代表一个集合。
item
:指向单一的元素个体,可以用/items/{itemID}
来表示特定的某个元素。items
:它便是一个集合资源,涵盖了众多元素个体,可以使用/items
来表示数据的集合资源。/items/{itemID}/elements
:单个资源也可能包含集合数据,比如一个item可能有很多个元素,我们用elements来表示。
这样的命名方式不仅有助于我们更清晰地理解和组织资源,还能提升Restful架构的易用性和扩展性。
不要在请求路径上加入CRUD操作
在Restful服务中,CRUD(创建、读取、更新、删除)操作应当通过请求资源时所使用的HTTP方法来区分,而非直接在资源命名中体现。
以获取items信息为例
shell
HTTP GET /items
我们应将资源定义为/items,而非/get-items。通过采用适当的HTTP请求方法,如GET请求,即可明确表示所需的操作类型。
查询过滤条件数据
在实际应用中,我们时常需要根据某些特定资源的属性进行排序、过滤或限制集合的返回,更推荐在已有的资源集合API中集成排序、过滤和分页功能,并将相关的输入参数作为查询参数进行传递。
shell
//查询对应的名称为name的数据
/users?queryName=name
//查询对应的名称为name的数据,并且基于age年龄进行正序排序,并且基于id进行desc倒序
/users?queryName=name&orderAge=asc&id=desc
//查询对应的名称为name的数据,并且基于age年龄进行正序排序,并且基于id进行desc倒序,并且分页为10,当前页数为2
/users?queryName=name&orderAge=asc&id=desc&pageSize=10&pageNum=2
通过在API请求中附带特定的查询参数,我们可以轻松地实现对资源的精确筛选和排序,从而满足各种复杂的业务需求。这种设计方式不仅减少了API的数量和维护成本,还提高了系统的灵活性和可扩展性。
资源操作类型
加载资源
在Restful服务中,加载资源这一动作,实则是对单个对象实例或数据库记录的访问与提取。我们可以将其视作从资源集合中精准定位并提取出的单一资源。
shell
// 加载汽车信息,在汽车系统里面,因为内部会由很多汽车,因此采用的cars的前缀路径
/cars/{car-id}
// 加载人群中某一个人的信息,基于这个人的id标识。
/users/{user-id}
// 我们假设任务系统里面只有一个关于root用户,因此直接用此表示直接获取root用户的信息
/users/root
查询资源
查询资源这一概念在Restful服务中,实际上可视为服务器所维护的资源集合,其内蕴含着众多资源项。客户端在交互过程中,可能会有向此集合添加新资源的需求。我们对于查询集合资源通常用在资源对象后面加入s
来表示。
shell
// 查询汽车集合,在汽车系统里面,查询所有的汽车数据组成一个集合,返回给客户端
/cars
// 查询用户集合,在员工系统里面,查询所有的用户数据组成一个集合,返回给客户端
/users
// 查询用户集合,在员工系统里面,查询所有这个角色的账号信息组成的一个集合,返回给客户端
/users/{roles}/accounts
存储资源
Restful服务中存储扮演着客户端管理的资源库的重要角色。对于这一资源库的增删改查操作,完全取决于API客户端如何调用相应的接口。
shell
// 更新对应的用户对应的汽车数据
HTTP PUT /users/{id}/cars
// 新增对应的用户对应的铅笔数据
HTTP POST /users/{id}/pencils
注意,为了更准确地表达资源的集合性质,通常使用复数形式来表示存储。
操作资源
操作资源实际上代表的是一个过程或行为的执行。它类似于一个可执行的函数,具备参数和返回值,涉及到输入和输出的概念。
shell
// 将这个用户的车退出到车库外
/users/{id}/cars/exit
// 将这个用户的车进入到车库里
/users/{id}/cars/enter
通常使用动词来描述这些操作资源,以更直观地表达其执行的动作和行为,这样的命名方式有助于我们更清晰地理解资源的操作方式。
最后总结
最后总结,本篇文章主要分析了Rest与Restful架构的核心概念,特别是关于资源如何被定义和命名的问题。在Restful架构中,资源占据着举足轻重的地位,如何对其进行精准定义和命名,直接关系到整个系统的稳定性和易用性。