Spring Boot RESTFul Web服务介绍

x33g5p2x  于2022-09-18 转载在 Spring  
字(4.0k)|赞(0)|评价(0)|浏览(332)

要理解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网络服务的属性

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 Web服务的分层系统

客户端可能不必知道它所请求的资源的服务器背后是什么。客户端可以调用订单服务,订单服务可以在内部从另一个服务中查询股票和价格细节。这种方法进一步实现了关注点的分离,从而让每个组件单独发展。


分层系统

按需编码

这是由RESTful网络服务规范规定的可选约束。在网络API请求中,请求和响应通常是JSON或XML。如果客户允许,你可以将可执行的内容作为响应提供给客户,例如,JSONP、APPLETS等。

统一的接口

对于网络服务来说,客户端可以是任何形式的。它可以是一个移动应用、一个网站、一个智能设备甚至是另一个服务。对于不同类型的客户端,一旦我们开始编写特定平台的代码,代码就会变得很笨拙。REST希望避免这些类型的情况。一个RESTful系统对于所有类型的客户端都应该有一个单一的接口。无论哪种类型的客户端发出请求,服务器都应该有相同的行为,这就是我们所说的统一接口。


所有客户都同意单一的请求响应格式

统一接口是一个服务成为RESTful的核心约束条件。这个约束规定了RESTful系统中的每个组件应该如何相互通信。这个约束的主要目标是提供一套子约束,以简化客户端和服务器如何在以下方面达成一致。

  1. 在哪里寻找资源
  2. 如何寻找资源
  3. 如何同意一个客户和服务器都能理解的格式
  4. 上述所有内容是否在整个系统中得到实施

我们将详细了解这些次级约束。

资源识别请求

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表示服务器不在接受状态或无法处理该请求。

Web服务端点的超媒体引用(HATEOAS)。

在对一个资源的响应中,我们可能不代表其所有的子/父资源。在这些情况下,我们需要在服务器的资源响应中指向正确的资源。但我们已经用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/itemsaccount字段也是如此,它与这个特定的订单有关。

###restful web服务的优点。

  1. 由于其无状态的性质,restful服务更容易扩大和缩小规模。
  2. 组件是基于逻辑层分割的。所以升级独立的组件可以更容易。这就是为什么大多数的微服务都采用RESTful方法。
  3. 明确的操作指令。正如我们前面看到的,每个HTTP方法都与一个HTTP动词同义。这样就不需要复杂的API文档了。例如,一个开发者会推断出,如果他需要删除一个资源,他需要调用HTTP.DELETE方法。
  4. 有了适当的缓存,服务器的负载就会大大减少。不存储状态的好处是增加了服务器的性能。
  5. 客户端拥有大部分的控制权。

为了让你学习,我们的SpringHow GitHub organization中有各种restful例子。请随意尝试。

相关文章