Spring Cloud - 网关

简介

在分布式环境中,服务需要相互通信。 但是,这是服务间通信。 我们也有这样的用例,我们域外的客户想要访问我们的 API 服务。 因此,我们可以公开所有可以由客户端调用的微服务的地址,或者我们可以创建一个服务网关,将请求路由到各种微服务并响应客户端。

在这里创建网关是更好的方法。 有两大优势 −

  • 不需要维护每个单独服务的安全性。

  • 而且,横切关注点,例如,添加元信息可以在一个地方处理。

Netflix ZuulSpring Cloud Gateway 是两个著名的云网关,用于处理此类情况。 在本教程中,我们将使用 Spring Cloud Gateway。


Spring Cloud Gateway – 依赖设置

让我们使用我们一直在使用的 Restaurant 餐厅案例。 让我们在我们的两个服务之前添加一个新服务(网关),即 Restaurant 餐厅服务和客户服务。 首先,让我们使用以下依赖更新服务的 pom.xml

<dependencies>
   <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
   </dependency>
   <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-gateway</artifactId>
   </dependency>
</dependencies>

然后,使用正确的注解来注解我们的 Spring 应用程序类,即 @EnableDiscoveryClient。

package com.tutorialspoint;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class RestaurantGatewayService{
   public static void main(String[] args) {
      SpringApplication.run(RestaurantGatewayService.class, args);
   }
}

我们使用 @EnableDiscoveryClient 进行注解是因为我们想使用 Eureka 服务发现来获取服务于特定用例的主机列表


带网关的动态路由

Spring Cloud Gateway 包含三个重要部分。 那些是 −

  • Route − 这些是网关的构建块,其中包含将请求转发到的 URL 以及应用于传入请求的谓词和过滤器。

  • Predicate − 这些是应该匹配传入请求转发到内部微服务的一组标准。 例如,仅当传入 URL 包含该路径时,路径谓词才会转发请求。

  • Filters − 这些充当您可以在将请求发送到内部微服务或响应回客户端之前修改传入请求的地方。

让我们为 Restaurant 餐厅和客户服务的网关编写一个简单的配置。

spring:
   application:
      name: restaurant-gateway-service
   cloud:
      gateway:
      discovery:
         locator:
            enabled: true
      routes:
         - id: customers
            uri: lb://customer-service
            predicates:
            - Path=/customer/**
         - id: restaurants
            uri: lb://restaurant-service
            predicates:
            - Path=/restaurant/**
server:
   port: ${app_port}
eureka:
   client:
      serviceURL:
         defaultZone: http://localhost:8900/eureka

上述配置的注意事项 −

  • 我们启用了 discovery.locator 以确保网关可以从 Eureka 服务器读取。

  • 我们在这里使用了 Path predicated 来路由请求。 这意味着任何以 /customer 开头的请求都将被路由到客户服务,对于 /restaurant,我们将把该请求转发给 Restaurant 餐厅服务。

现在让我们在网关服务之前设置其他服务 −

  • 启动 Eureka 服务

  • 启动 Customer 服务

  • 启动餐厅服务

现在,让我们编译并执行 Gateway 项目。 我们将使用以下命令进行相同的操作 −

java -Dapp_port=8084 -jar .\target\spring-cloud-gateway-1.0.jar

完成后,我们就可以在端口 8084 上测试网关了。让我们首先点击 http://localhost:8084/customer/1,我们看到请求被正确路由到客户服务,我们得到以下输出 −

{
   "id": 1,
   "name": "Jane",
   "city": "DC"
}

现在,点击我们的餐厅 API,即 http://localhost:8084/restaurant/customer/1,我们得到以下输出 −

[
   {
      "id": 1,
      "name": "Pandas",
      "city": "DC"
   },
   {
      "id": 3,
      "name": "Little Italy",
      "city": "DC"
   }
]

这意味着两个呼叫都正确路由到了各自的服务。


谓词和过滤器请求

我们在上面的示例中使用了路径谓词。 以下是一些其他重要的谓词 −

谓词 说明
Cookie predicate (input: name and regex) 将带有"name"的cookie与"regexp"进行比较
Header predicate (input: name and regex) 将带有"name"的标题与"regexp"进行比较
Host predicate (input: name and regex) 将传入的"name"与"regex"进行比较
Weight Predicate (input: Group name and the weight) Weight Predicate (input: Group name and the weight)

过滤器用于在将数据发送到下游服务或将响应发送回客户端之前从请求中添加/删除数据。

以下是一些用于添加元数据的重要过滤器。

过滤器 说明
Add request header filter (input: header and the value) 在向下游转发请求之前添加"header"和"value"。
Add response header filter (input: header and the value) 在将请求上游转发给客户端之前添加"header"和"value"。
Redirect filter (input: status and URL) 在通过下游主机之前添加重定向标头以及 URL。
ReWritePath (input: regexp and replacement) 这负责通过用输入替换替换"regexp"匹配的字符串来重写路径。

过滤器和谓词的详尽列表位于 https://cloud.spring.io/spring-cloudgateway/reference/html/#the-rewritepath-gatewayfilter-factory


监控

为了监控网关或者访问各种路由、谓词等,我们可以在项目中启用执行器。 为此,让我们首先更新 pom.xml 以包含执行器作为依赖项。

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

对于监控,我们将使用一个单独的应用程序属性文件,其中包含启用执行器的标志。 所以,这就是它的样子 −

spring:
   application:
      name: restaurant-gateway-service
   cloud:
      gateway:
         discovery:
            locator:
               enabled: true
         routes:
            - id: customers
              uri: lb://customer-service
              predicates:
              - Path=/customer/**
            - id: restaurants
              uri: lb://restaurant-service
              predicates:
              - Path=/restaurant/**
server:
   port: ${app_port}
eureka:
   client:
      serviceURL:
         defaultZone: http://localhost:8900/eureka
management:
   endpoint:
      gateway:
         enabled: true
   endpoints:
      web:
         exposure:
            include: gateway

现在,要列出所有路由,我们可以点击:http://localhost:8084/actuator/gateway/routes

[
   {
      "predicate": "Paths: [/customer/**], match trailing slash: true",
      "route_id": "customers",
      "filters": [],
      "uri": "lb://customer-service",
      "order": 0
   },
   {
      "predicate": "Paths: [/restaurant/**], match trailing slash: true",
      "route_id": "restaurants",
      "filters": [],
      "uri": "lb://restaurant-service",
      "order": 0
   }
]

其他重要的监控 API −

API 说明
GET /actuator/gateway/routes/{id} 获取有关特定路由的信息
POST /gateway/routes/{id_to_be assigned} 向网关添加新路由
DELETE /gateway/routes/{id} 从网关中删除路由
POST /gateway/refresh 删除所有缓存条目