1.Spring Cloud Gateway 是什么?
它是一个基于 Spring Framework 的开源 API 网关服务。它旨在为微服务架构中的应用程序提供统一的路由和过滤器机制,以实现请求的转发、降级、熔断、限流等功能。换言之,它就是网关(Gateway),充当了客户端和内部微服务之间的中介。
Spring Cloud Gateway 组成:
- 路由:定义请求应该被转发到哪个目标地址。
- 断言:用于匹配请求的条件,根据断言条件匹配到相应的路由。
- 过滤器:用于在请求路由前或路由后进行一些处理、操作,比如添加头部信息、修改请求体等。
在微服务中,内部之间的通讯是用 OpenFeign + LoadBalancer
实现的。那前端向后端发送请求的时候,我的访问路径是什么呢?该向哪一个服务发送呢?该用什么来统筹外部与内部之间的通信呢?其实就是使用 Spring Cloud Gateway
来提供统一访问地址或者定义一些规则来处理请求。
2. Gateway 的路由功能
2.1 准备工作
创建两个模块,来实现 Gateway 的路由功能。gateway-service
为网关,user-service
为一个服务。
在 gateway-service
的 pom. xml
中,添加依赖:
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
在 user-service
的 pom. xml
中,添加依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
注意,
Spring Cloud Gateway
不能配合Spring Web(Spring MVC)
一起使用。也就是在同一个pom
文件中不能同时存在。
在 user-service
模块中随便写一个接口,然后配置 gateway
来实现路由的转发。
java
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/getname")
public String getName(){
return "Name: 小明";
}
}
2.2 配置路由
现在配置 gateway
:
yml
spring:
cloud:
gateway:
routes:
- id: userservice
uri: http://localhost:9090
predicates:
- Path=/user/**
server:
port: 8080
下面是 properties
格式的:
properties
server.port=8080
spring.cloud.gateway.routes[0].id=userservice
spring.cloud.gateway.routes[0].uri=http://localhost:9090
spring.cloud.gateway.routes[0].predicates[0]=Path=/user/**
- id:
userservice
,表示这个路由的唯一标识,不能重复,没有其他作用。 - uri:
http://localhost:9090
,表示这个路由的目标地址。 - predicates: 表示这个路由的断言列表,它有很多种类型,更多的类型后文介绍。
- Path=/user/,表示这个断言的类型是
Path
,用于匹配请求路径,这里表示匹配以/user/
开头的任意路径。
这个路由规则的意思是,如果请求路径以/user/
开头,就转发到http://localhost:9090
这个地址。
user-service
配置:
yml
server:
port: 9090
启动程序后:
可以看到,localhost: 8080/user/getname
能访问到 9090
端口的 user-service
服务。这就实现了 localhost: 8080/user/getname
到 localhost: 9090/user/getname
路径的转换。
如果一个模块中有多个路由需要转换,就可以使用英文逗号隔开:
yml
spring:
cloud:
gateway:
routes:
- id: userservice
uri: http://localhost:9090
predicates:
- Path=/user/**,/us/**,......
server:
port: 8080
2.3 多个模块
再添加一个模块 goods-service
java
@RestController
@RequestMapping("/goods")
public class GoodsController {
@RequestMapping("/getname")
public String getGoodsName(){
return "红旗汽车";
}
}
yml
server:
port: 7070
由于新增加一个模块,那么就需要添加一个路由设置。gateway
的配置文件:
yml
spring:
cloud:
gateway:
routes:
- id: userservice
uri: http://localhost:9090
predicates:
- Path=/user/**
- id: goodsservice
uri: http://localhost:7070
predicates:
- Path=/goods/**
server:
port: 8080
启动程序,并访问 localhost: 8080/goods/getname
可以看到 gateway
将不同的端口的服务整合到一起,这就是它的作用之一。
2.4 断言类型
Gateway 的断言类型有:
- After、Before、Between:根据请求的时间进行路由,可以指定一个时间点或一个时间区间。
- Cookie:根据请求中的cookie进行路由,可以指定cookie的名称和值的正则表达式。
- Header:根据请求头进行路由,可以指定请求头的名称和值的正则表达式。
- Host:根据请求的主机名进行路由,可以指定一个或多个主机名,也可以使用通配符。
- Method:根据请求的方法进行路由,可以指定一个或多个HTTP方法,如GET、POST等。
- Query:根据请求的查询参数进行路由,可以指定参数的名称和值的正则表达式。
- Path:匹配请求路径。
- Query:匹配请求参数。
- RemoteAdder:匹配请求的 IP 地址。
- Weight:根据权重来分发请求。
- XForwardedRemoteAddr:根据 HTTP 头 X-Forwarded-For 进行请求过滤。
(更详细的看官方文档: Spring Cloud Gateway)
2.4.1 根据时间匹配
下面表示在 2024-01-28 T17:42:47.789
这个时间之后才会匹配路由,+08:00[Asia/Shanghai]
为时区。
yml
spring:
cloud:
gateway:
routes:
- id: userservice
uri: http://localhost:9090
predicates:
- Path=/user/**
- After=2024-01-28T17:42:47.789+08:00[Asia/Shanghai]
在 2017-01-20 T17:42:47.789~2017-01-21 T17:42:47.789
之间的请求可以被匹配。
yml
spring:
cloud:
gateway:
routes:
- id: userservice
uri: http://localhost:9090
predicates:
- Path=/user/**
- Between=2017-01-20T17:42:47.789+08:00[Asia/Shanghai], 2017-01-21T17:42:47.789+08:00[Asia/Shanghai]
2.4.2 Header 断言
yml
spring:
cloud:
gateway:
routes:
- id: userservice
uri: http://localhost:9090
predicates:
- Path=/user/**
- id: goodsservice
uri: http://localhost:7070
predicates:
- Path=/goods/**
- Header=X-Request-Id, \d+
这个路由匹配条件是:如果请求包含名为 X-Request-Id
的头,并且该头的值与正则表达式 \d+
匹配(即,它的值为一个或多个数字),则路由匹配。
(正则表达式的规则:正则表达式 -- 教程 | 菜鸟教程 (runoob.com))
没有 X-Request-Id
时 404:
添加 X-Request-Id
时,能访问:
2.4.3 Method 断言
yml
spring:
cloud:
gateway:
routes:
- id: userservice
uri: http://localhost:9090
predicates:
- Path=/user/**
- id: goodsservice
uri: http://localhost:7070
predicates:
- Path=/goods/**
- Method=GET,POST
只能匹配 GET、POST
类型的请求。
2.4.4 Weight 断言
yml
spring:
cloud:
gateway:
routes:
- id: userservice1
uri: http://localhost:9090
predicates:
- Weight=group1,10
- id: userservice2
uri: http://localhost:7070
predicates:
- Weight=group1,90
假设 userservice1
与 userservice2
模块都有"/user/getname
"这个接口。上面的意思是:把大约 10%
的流量转发到 userservice1
,而将大约 90%
的流量转发到 userservice2
。要注意的是权重是按组计算 的,上面的两个模块同属于 group1
,那么就将这一组按比例来分流。
(最后,Gateway
肯定需要结合 Nacos
和 LoadBalancer
来使用,这样才能发挥它的最大作用,本篇只介绍了 Gateway 的断言,其它(如过滤器)后续再更新......)