微服务你得知道这些!从核心组件到远程调用方式以及 HTTP 通信方法

如果一个架构符合 REST 的约束条件和原则,就称它为 RESTful 架构,当然理论上 REST 架构风格并不是绑定在 HTTP 上的,只不过目前 HTTP 是唯一与 REST 相关的实现,所以一般情况下 REST API 都是表示基于 HTTP 的 RESTful 接口。
既然是一种标准、一种架构风格,就必然会有它的相关概念和设计原则。表 2.1 所示为 REST API 中的一些重要术语。

同时,REST API 也有很多设计原则,如 URL 中永远不能包含动词,那么 URL 如何表示自己的行为呢?前面提到过 4 种常见的行为(查看、创建、编辑和删除)映射到 HTTP 中已实现的方法中,具体如下。
(1)GET(查看):从服务器或资源列表中检索特定资源。
(2)POST(创建):在服务器上创建一个新资源。
(3)PUT(编辑):更新服务器上的资源,提供整个资源。
(4)PATCH(编辑):更新服务器上的资源,仅提供已更改的属性。
(5)DELETE(删除):从服务器中删除资源。
下面两个不是很常用。
(1)HEAD(查看):检索有关资源的元数据,如数据的哈希值或上次更新的时间。
(2)OPTIONS(查看):检索有关允许消费者使用资源的信息。客户端和服务端的交互是无状态的,GET 请求通常是可以被缓存的,资源使用复数,URL 中可以有表述版本的信息,举例如下。

按照顺序对应的含义如下。
(1)使用 2.0 版本的接口,创建一个产品。
(2)使用 2.0 版本的接口,根据 ID 查看产品信息。
(3)使用 1.0 版本的接口,根据 ID 全量更新产品信息。
(4)使用 1.0 版本的接口,根据 ID 部分更新产品信息。
(5)使用 1.0 版本的接口,根据 ID 删除产品。
RESTful 的接口还有很多设计原则,这里不再赘述,感兴趣的读者可以查阅相关资料进行学习,在微服务中使用的 HTTP 通信协议就是采用的 RESTful 的接口设计,所以熟练掌握 REST API 的设计用法在微服务架构中是十分重要的。
HTTP 通信方法
========
一般在项目中采用什么技术来完成 HTTP 通信?在一些早期的项目中,可以看到 Apache HttpComponents 的身影,它的功能也十分强大,但是在使用时,需要编写大量的基础代码,往往还需要进行二次封装,而在如今 Spring Boot 盛行的时代,大家更热衷于现取现用,正所谓约定大于配置,所有的基础工作都按照一定的约定交由框架来完成。下面以 Spring 为例,主要介绍 RestTemplate 和 WebClient 两种方式进行 HTTP 的通信。
1. RestTemplateRestTemplate 是 Spring Web 中提供的用于在客户端完成同步的 HTTP 请求的核心类,大大简化了与 HTTP 服务器的通信,并实现了 RESTful 的设计原则。RestTemplate 默认采用 JDK 原生的 HTTP 连接工具实现,当然也可以切换库,如 Apache HttpComponents、Netty 和 OKHttp 等第三方的 HTTP 库。我们以默认的实现为例,首先需要声明一个 RestTemplate,这里采用 Spring Boot 的注解式声明方式,代码如下。

当然,还可以给它初始化一些公共属性,如 URL、用户名密码,或者一些连接超时等设置,代码如下。

完成 RestTemplate 的声明之后就可以使用它了 , 之前说过 RestTemplate 实现了 RESTful 的设计原则,所以 RestTemplate 提供了便捷的方法去实现 HTTP 的 GET、POST、PUT、PATCH 和 DELETE 方法。例如,getForEntity()就是以 GET 的方式发送 HTTP 请求,而 postForEntity()则 是 以 POST 的 方 式 发 送 HTTP 请 求 。 当 然 , 还 有 其 他 实 现 , 如 patchForObject()、put()、delete()和 optionsForAllow()等方法,这里就不一一介绍了。下面以 GET 和 POST 两种最常见的方式来介绍 RestTemplate 的用法,其他的大同小异。
(1)RestTemplate 的 GET 方法。
RestTemplate 提供了 getForObject 和 getForEntity 两种方式发送 GET 的 HTTP 请求,其中 getForObject 方法可以直接将响应的 Body 转换为指定的类型,方法定义如下。

其中,第一个方法比较常用,按照顺序传递 URL 的参数,通过在 URL 中定义{}来表示参数的站位,{}中可以写具体含义的单词,也可以写数字,如{0},代码如下。

此外,getForObject 还提供了另外两种重载方法,分别提供了通过 Map 传递参数和没有参数两种功能。没有参数很好理解,不再赘述,下面的代码展示了通过 Map 传递参数的方式。

不难看出,Map 中的 key 对应着 URL 中{}里的单词,使用 Map 的不足之处是当参数太多时,顺序容易弄错,而且方法会写得很长,不易读,也不易维护。getForObject 方法能满足我们大部分的需求,但有时可能需要获取除 Body 之外的信息,如响应头、响应状态码等,这时就需要 getForEntity 了,getForEntity 和 getForObject 一样,提供了 3 种实现,方法定义如下。

可以发现,getForEntity 的方法参数和 getForObject 的一样,唯一的区别是 getForEntity 的返回类型是 ResponseEntity。这里不再对每个方法进行详细介绍了,下面还是以第一个方法为例,代码如下。

(2)RestTemplate 的 POST 方法。
与 GET 的方式一样,POST 也提供了 postForObject 和 postForEntity 两种方式来完成 POST 的 HTTP 请求。方法定义如下。

POST 的 6 个方法定义与 GET 几乎一样,所以这里没有把方法说明粘贴进来,仔细观察可以发现,POST 的方法多了一个 request 的参数,这个参数会被放进请求的 Body 中,当没有需要时也可以传入 null,举例如下:

关于 RestTemplate 的其他方法就不再列举了,感兴趣的读者可以查看 Spring Web 库的源码,或者访问 Spring 的官网查阅相关教程。
2. WebClient
WebClient 相比 RestTemplate 是一个较新的 HTTP 访问方式,之前提到过,RestTemplate 是一个同步的请求方式,当请求发出后,当前线程会等待,直到有响应后才会继续执行后续代码。其实远程调用是一个可以异步的过程,在等待请求响应时,我们完全可以做其他的事情,所以 RestTemplate 在一些性能要求比较高的地方使用就显得不是那么合适了。

评论