Spring Cloud 网关

本文将介绍 Spring Cloud Gateway。

一、微服务网关

微服务网关将作为微服务系统的唯一入口,为外界提供 API 访问的功能。

二、Gateway

1. 什么是 Gateway?

Gateway,Spring Cloud Gateway,是 Spring Cloud 下的微服务网关组件。

2. 路由

路由是 Gateway 中的基本转发规则,声明方式有:

  • 通过 Java 代码声明路由:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Bean
    public RouteLocator declare(RouteLocatorBuilder builder) {
    return builder
    .routes()
    .route("id-001", route -> route
    .path("/geekbang/**")
    .uri("http://time.geekbang.org")
    )
    .build();
    }
  • 通过配置文件声明路由:

    1
    2
    3
    4
    5
    6
    7
    8
    spring:
    cloud:
    gateway:
    routes:
    - id: id-001 # 路由ID
    uri: http://time.geekbang.org # 目标地址
    predicates: # 谓词列表
    - Path=/geekbang2/**
  • 基于 Nacos 声明 动态路由 ,略

3. 谓词

(1) 什么是谓词?

所谓谓词,实际上是路由的判断规则。

(2) 内置谓词

Gateway 提供了大量内置谓词,常见的有:

  • 请求路径谓词 path:

    1
    2
    3
    .route("id-001", route -> route
    .path("/geekbang/**")
    .uri("http://time.geekbang.org")
  • 请求方法谓词 method:

    1
    2
    3
    4
    5
    .route("id-001", route -> route
    .path("/geekbang/**")
    .and()
    .method(HttpMethod.GET, HttpMethod.POST)
    .uri("http://time.geekbang.org")
  • 请求参数谓词 cookie、header、query:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    .route("id-001", route -> route
    .path("/geekbang/**")
    .and()
    .method(HttpMethod.GET, HttpMethod.POST)
    .and()
    .cookie("myCookie", "regex")
    .and()
    .header("myHeaderA")
    .and()
    .header("myHeaderB", "regex")
    .and()
    .query("paramA")
    .uri("http://time.geekbang.org")
  • 时间谓词 before、after、between:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    .route("id-001", route -> route
    .path("/geekbang/**")
    .and()
    .method(HttpMethod.GET, HttpMethod.POST)
    .and()
    .cookie("myCookie", "regex")
    .and()
    .header("myHeaderA")
    .and()
    .header("myHeaderB", "regex")
    .and()
    .query("paramA")
    .and()
    .before(ZonedDateTime.parse("2022-12-25T14:33:47.789+08:00"))
    .or()
    .after(ZonedDateTime.parse("2022-12-25T14:33:47.789+08:00"))
    .uri("http://time.geekbang.org")

    (3) 配置路由 - 自定义谓词

Gateway 也支持自定义谓词,从而实现自定义的路由条件配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 继承自通用扩展抽象类AbstractRoutePredicateFactory
public class MyPredicateFactory extends
AbstractRoutePredicateFactory<MyPredicateFactory.Config> {

public MyPredicateFactory() {
super(Config.class);
}

// 定义当前谓词所需要用到的参数
@Validated
public static class Config {
private String myField;
}

@Override
public List<String> shortcutFieldOrder() {
// 声明当前谓词参数的传入顺序
// 参数名要和Config中的参数名称一致
return Arrays.asList("myField");
}

// 实现谓词判断的核心方法
// Gateway会将外部传入的参数封装为Config对象
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return new GatewayPredicate() {

// 在这个方法里编写自定义谓词逻辑
@Override
public boolean test(ServerWebExchange exchange) {
return true;
}

@Override
public String toString() {
return String.format("myField: %s", config.myField);
}
};
}
}

4. 过滤器

Gateway 中,过滤器负责 “过滤” 请求和响应。

5. 示例

(1) 引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- Gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<!-- Nacos - 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!-- 负载均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

(2) 接入服务治理

增加服务治理相关配置,使得 Gateway 服务接入服务治理组件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
spring:
cloud:
nacos:
discovery:
# 命名空间
namespace: dev
# 分组
group: myGroup
# 服务ID
service: Mall-Gateway
# Nacos地址 [可以配置多个,逗号分隔]
server-addr: localhost:8848
# 心跳时间间隔,时间单位是ms
heart-beat-interval: 5000
# 超过一定时间未收到心跳就标记为不健康,默认为15s
heart-beat-timeout: 20000
# 是否在启动时读取服务列表缓存 [若true。则会在本地文件中保存服务列表,在启动时读取]
naming-load-cache-at-start: false
# 向注册中心注册服务,默认为true [如果只消费服务,不作为服务提供方,可以设置成false以减少开销]
register-enabled: true

(3) 整合服务治理

增加配置,使得 Gateway 可以通过服务发现来获取服务。

1
2
3
4
5
6
7
spring:
cloud:
gateway:
discovery:
locator:
# 是否启用服务发现 [通过服务发现来获取所有服务]
enabled: true

(4) 声明路由

通过 Java 代码的形式声明路由,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Configuration
public class RoutesConfiguration {

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
// 商品服务
.route(
"product_route",
router -> router
.path("/mall-product/**")
// 去掉前缀 [/mall-product/** -> /**]
.filters(f -> f.stripPrefix(1))
.uri("lb://Mall-Product"))
// 订单服务
.route(
"order_route",
router -> router
.path("/mall-order/**")
// 去掉前缀 [/mall-order/** -> /**]
.filters(f -> f.stripPrefix(1))
.uri("lb://Mall-Order"))
.build();
}
}

(5) 访问路由

通过 host:port/前缀/路径 即可借助 Gateway 访问到背后的 API。

参考

  • Spring Cloud 微服务项目实战