要理解RESTful API或RESTful Web服务,你首先需要理解什么是API。API(Application Programming Interface)是一种软件/应用/库/机制,帮助一个程序与另一个程序进行通信。最广泛使用的API类型是Web-API或Web服务。在这种类型中,客户发送一个HTTP请求,而服务器发送回一个HTTP响应。
例如,如果你在一个银行网站上,你想看看余额,浏览器向银行服务器发送一个请求,得到一个包含相关账户详情的响应。
REpresentational State Transfer(REST)是一套软件设计准则,用于开发通过HTTP交互的应用程序。如果一个网络API遵循REST的架构约束,那么它就可以被称为RESTful API。
RESTful API存在的原因是它所承诺的架构属性。RESTful网络服务应该有以下属性
根据定义,网络服务应该符合以下架构约束,以成为一个RESTFul网络服务或RESTful API。我将逐一介绍它们的含义。
在RESTFul网络服务中,这种约束背后的主要关注点是分离。例如,在一个购物网站中,将账户相关的组件从库存和订单中移开是一件好事,因为我们可以单独扩展这些组件中的每个。订单组件可以作为一个客户端,并在需要时向支付和库存网络服务执行API请求。这也提高了可扩展性,因为每个独立的组件可以独立发展。
客户端服务器模型--关注点的分离
看一下这个示例代码。
@GetMapping("/nextPage")
List<Orders> getNextOrders() {
currentPage = currentPage +1 ;
return getPage(currentPage);
}
Code language: PHP (php)
这段代码的问题是,服务器维护着客户端想要做的事情的状态。而这个状态是在两次请求之间保持的。这就是我们所说的有状态的系统。这些类型看起来很简单,但实际很复杂,因为客户端现在需要确定它将得到哪个页面。
当服务器在每次请求之间不维护任何状态时,系统就是无状态的。请看下面的代码,与我们之前试图解决的问题相同。
@GetMapping("/pages/{pageNumber}")
List<Orders> getNextOrders(@PathVariable Integer pageNum) {
return getPage(pageNum);
}
Code language: CSS (css)
在这个实现中,服务器并不保留当前的页码。客户端可以控制它想读哪一页。
由于REST相信万维网的HTTP概念,客户端和中间人在可能的情况下可以缓存响应。服务器和客户端必须提供足够的提示,让对方知道他们是否支持缓存。在一个理想的REST服务中,缓存部分或完全消除了客户端与服务器之间的互动,从而提高了可扩展性和性能。
客户端可能不必知道它所请求的资源的服务器背后是什么。客户端可以调用订单服务,订单服务可以在内部从另一个服务中查询股票和价格细节。这种方法进一步实现了关注点的分离,从而让每个组件单独发展。
分层系统
这是由RESTful网络服务规范规定的可选约束。在网络API请求中,请求和响应通常是JSON或XML。如果客户允许,你可以将可执行的内容作为响应提供给客户,例如,JSONP、APPLETS等。
对于网络服务来说,客户端可以是任何形式的。它可以是一个移动应用、一个网站、一个智能设备甚至是另一个服务。对于不同类型的客户端,一旦我们开始编写特定平台的代码,代码就会变得很笨拙。REST希望避免这些类型的情况。一个RESTful系统对于所有类型的客户端都应该有一个单一的接口。无论哪种类型的客户端发出请求,服务器都应该有相同的行为,这就是我们所说的统一接口。
所有客户都同意单一的请求响应格式
统一接口是一个服务成为RESTful的核心约束条件。这个约束规定了RESTful系统中的每个组件应该如何相互通信。这个约束的主要目标是提供一套子约束,以简化客户端和服务器如何在以下方面达成一致。
我们将详细了解这些次级约束。
RESTFul Web服务中的资源是一个类似于面向对象编程中的对象,或者是一个数据库中的实体。它可以是一个网页,一个单一的对象或一个实体。它甚至可以代表任何任意的内容。由于这种性质,我们需要解决这些独特的资源,REST设计原则建议我们使用URI。
通过使用URLs,我们可以将资源按层次顺序排列。让我们举一个例子。在一个订单管理系统中,下面的列表将解释我们如何将资源表示为URLs。
/orders
所有订单。/orders/{orderId}
有特定订单号的订单/orders/{orderId}/items
该订单中的所有项目/orders/{orderId}/items/{itemId}
一个订单中的单个项目/orders/{orderId}/account
哪个账户订购了它。/accounts/
系统中所有账户的列表/accounts/{accountId}
具体的账户这些URI的实际内容应该为客户端提供足够的信息,以执行必要的任务。例如,客户在查看订单时得到账户的数据。这样客户就可以回到accounts
的列表中,如果他们想找到相关的orders
。一旦我们接受了这个逻辑,REST APIs就会变得更容易理解。
有时,你可能无法在RESTful服务中给出所有的信息。例如,子对象可能有太多的信息,会增加响应的大小。客户端应该能够按照URI来获取必要的信息。这种类型的实现被称为HATEOAS(Hypertext As The Engine Of Application State)。
客户端可以对URI标识的资源进行CRUD操作(如果客户端有足够的权限)。这里的好处是URI可以是一个URL,因此我们可以将每个CRUD操作映射成一个HTTP接口。
HTTP方法 | 对URI的预期操作 |
---|---|
GET | 读取URI所指向的资源。 |
POST | 在所指的URI上创建一个资源。理想的实现应该返回所创建资源的URI。 |
PUT | 用请求正文中的内容替换成员资源的所有表现形式,或者在不存在的情况下创建成员资源。 |
PATCH | 更新成员资源的所有表现形式,如果成员资源不存在,则可以使用请求正文中的指令创建成员资源。 |
DELETE | 删除该成员资源的所有表现形式。 |
我们前面谈到的每个操作的结果都是服务器的响应。在某些情况下,服务器会发送响应。在其他情况下,可能会有状态信息。由于我们使用HTTP进行通信,而且HTTP默认带有各种客户-服务器状态代码,所以我们不必发明新的状态消息或代码。比如说。
HTTP 2xx
表示成功。HTTP 3xx
可能代表重定向或Cache相关的指示。HTTP 4xx
表示客户端没有发送适当的请求。HTTP 5xx
表示服务器不在接受状态或无法处理该请求。在对一个资源的响应中,我们可能不代表其所有的子/父资源。在这些情况下,我们需要在服务器的资源响应中指向正确的资源。但我们已经用URI解决了这个问题。每个资源响应都可能包含其相关资源的URI,按照这些资源的URI,客户端就可以进行探索。这些被称为超媒体驱动的输出。而这种表现形式被称为HATEOAS(Hypertext As The Engine Of Application State)。例如,以订单资源的这个JSON输出为例。
{
"orderId": 1,
"total": 54.99,
"_links": {
"self": {
"href": "http://localhost:8080/orders/1"
},
"account": {
"href": "http://localhost:8080/accounts/2"
},
"items": {
"href": "http://localhost:8080/orders/1/items"
}
}
}
Code language: JSON / JSON with Comments (json)
这里订单的items
字段是一个项目的集合。因此,它在响应中会占用大量的字节。如果客户想要这些信息,它可以随时导航到http://localhost:8080/orders/1/items
。account
字段也是如此,它与这个特定的订单有关。
###restful web服务的优点。
HTTP.DELETE
方法。为了让你学习,我们的SpringHow GitHub organization中有各种restful例子。请随意尝试。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://springhow.com/restful-web-services-with-spring-boot/
内容来源于网络,如有侵权,请联系作者删除!