008-API网关-SpringCloudGateway
# 一、为什么要使用网关 (opens new window)
# 三、架构剖析
客户端(外部请求)向Spring Cloud Gateway
发出请求。Handler Mapping
会判断请求的路径是否匹配路由的配置,如果匹配,就会进入到Web Handler
,Web Handler会读取这个路由上配置的过滤器。把请求交给这些过滤器进行处理。
Gateway Handler Mapping:org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping (opens new window)
Gateway Web Handler:org.springframework.cloud.gateway.handler.FilteringWebHandler (opens new window)
# 三、编写SpringCloudGateway
# 3.1 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2
3
4
额外增加
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2
3
4
5
6
7
8
9
# 3.2 编写配置
server:
port: 8040
spring:
application:
name: gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
discovery:
locator:
# 让gateway通过服务发现组件找到其他的微服务
enabled: true
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 3.3 启动项目并测试
user-center服务
请求
GET:http://localhost:8040/user-center/users/1 (opens new window)
响应
{
"id": 1,
"wxId": "",
"wxNickname": "",
"roles": "",
"avatarUrl": "",
"createTime": "2021-05-04T06:34:35.000+0000",
"updateTime": "2021-05-04T06:34:35.000+0000",
"bonus": 400
}
2
3
4
5
6
7
8
9
10
content-center服务
请求
GET:http://localhost:8040/content-center/shares/1 (opens new window)
响应
{
"id": 1,
"userId": 1,
"wxNickname": "",
"title": "spring",
"createTime": "2021-05-05T22:57:01.000+0000",
"updateTime": "2021-05-05T22:57:04.000+0000",
"isOriginal": true,
"author": "xx",
"cover": "xxx",
"summary": "xxx",
"price": 0,
"downloadUrl": "xx",
"buyCount": 1,
"showFlag": true,
"auditStatus": "PASS",
"reason": "String"
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 3.4 转发规律
${gateway_url}/${微服务}/${目标URI}
# 四、核心概念
# Route(路由)
一条转发的规则。包含:ID、目标URL、Predcate集合以及Filter集合。
# Predicate(断言)
这是一个 Java 8 的 Predicate,可以使用它来匹配来自 HTTP 请求的任何内容,例如 headers 或参数。断言的输入类型是一个 ServerWebExchange。
# Filter(过滤器)
拦截和修改请求,并且对上游的响应,进行二次处理。过滤器为org.springframework.cloud.gateway.filter.GatewayFilter类的实例。
# 🧐 路由配置示例
spring:
cloud:
gateway:
routes:
- id: blog
uri: http://localhost:8010
predicates:
# 匹配路径转发
- Path=/api-boot-datasource-switch.html
2
3
4
5
6
7
8
9
# 五、内置路由断言工厂详解(RoutePredicateFactories)
# 六、自定义路由断言工厂(假设服务只有9:00 ~ 17:00才可以访问)
假设服务只有9:00 ~ 17:00才可以访问
# 6.1 创建一个自定义路由断言工厂
创建 TimeBetweenRoutePredicateFactory
继承 AbstractRoutePredicateFactory<TimeBetweenConfig>
😉类名必须以RoutePredicateFactory
结尾
泛型写配置类
@Component
public class TimeBetweenRoutePredicateFactory extends AbstractRoutePredicateFactory<TimeBetweenRoutePredicateFactory.TimeBetweenConfig> {
public TimeBetweenRoutePredicateFactory() {
super(TimeBetweenConfig.class);
}
@Override
public Predicate<ServerWebExchange> apply(TimeBetweenConfig config) {
final LocalTime start = config.getStart();
final LocalTime end = config.getEnd();
return serverWebExchange -> {
final LocalTime now = LocalTime.now();
return now.isAfter(start) && now.isBefore(end);
};
}
/**
* 控制配置类与配置文件的映射关系
*/
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("start", "end");
}
@Data
public static class TimeBetweenConfig {
private LocalTime start;
private LocalTime end;
}
}
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
配置类中的顺序由shortcutFieldOrder
指定
apply
控制路由的条件
# 6.2 添加配置
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
discovery:
locator:
# 让gateway通过服务发现组件找到其他的微服务
enabled: true
routes:
- id: after_route
uri: lb://user-center
predicates:
# # 当且仅当请求时的时间After配置的时间时,才会转发到用户微服务
# # 目前配置不会进该路由配置,所以返回404
# # 将时间改成 < now的时间,则访问localhost:8040/** -> user-center/**
# # eg. 访问http://localhost:8040/users/1 -> user-center/users/1
# - After=2030-01-20T17:42:47.789-07:00[America/Denver]
- TimeBetween=上午9:00,下午5:00
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 6.3 时间配置补充:
🧐 时间格式注册:
org.springframework.format.datetime.standard.DateTimeFormatterRegistrar#registerFormatters
通过改方法可以发现,LocalTime的格式化工具
DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
测试
public static void main(String[] args) {
final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);
System.out.println(dateTimeFormatter.format(LocalTime.now()));
}
2
3
4
5
响应
上午11:46
# 6.4 测试
测试时间:上午8:30
请求
GET:http://localhost:8040/users/1
响应
Whitelabel Error Page
This application has no configured error view, so you are seeing this as a fallback.
Sat Mar 05 11:35:28 CST 2022
There was an unexpected error (type=Not Found, status=404).
2
3
4
5
修改配置 - TimeBetween=上午8:00,下午5:00
请求
GET:http://localhost:8040/users/1
响应
{
"id": 1,
"wxId": "",
"wxNickname": "",
"roles": "",
"avatarUrl": "",
"createTime": "2021-05-04T06:34:35.000+0000",
"updateTime": "2021-05-04T06:34:35.000+0000",
"bonus": 400
}
2
3
4
5
6
7
8
9
10
# 七、内置过滤器工厂
- AddRequestHeader GatewayFilter Factory
- AddRequestParameter GatewayFilter Factory
- AddResponseHeader GatewayFilter Factory
- DedupeResponseHeader GatewayFilter Factory
- Hystrix GatewayFilter Factory
- FallbackHeaders GatewayFilter Factory
- PrefixPath GatewayFilter Factory
- PreserveHostHeader GatewayFilter Factory
- RequestRateLimiter GatewayFilter Factory
- RedirectTo GatewayFilter Factory
- RemoveHopByHopHeadersFilter GatewayFilter Factory
- RemoveRequestHeader GatewayFilter Factory
- RemoveResponseHeader GatewayFilter Factory
- RewritePath GatewayFilter Factory
- RewriteResponseHeader GatewayFilter Factory
- SaveSession GatewayFilter Factory
- SecureHeaders GatewayFilter Factory
- SetPath GatewayFilter Factory
- SetResponseHeader GatewayFilter Factory
- SetStatus GatewayFilter Factory
- StripPrefix GatewayFilter Factory
- Retry GatewayFilter Factory
- RequestSize GatewayFilter Factory
- Modify Request Body GatewayFilter Factory
- Modify Response Body GatewayFilter Factory
- Default Filters
# 八、自定义过滤器工厂
# 8.1 生命周期
- pre Gateway转发请求前
- post Gateway转发请求后
# 8.2 自定义过滤器工厂的方式
# 继承:AbstractGatewayFilterFactory
参考示例:org.springframework.cloud.gateway.filter.factory.RequestSizeGatewayFilterFactory (opens new window)
配置方式:
spring:
cloud:
gateway:
routes:
filters:
- name: RequestSize
args:
maxSize: 5000000
2
3
4
5
6
7
8
# 继承:AbstractNameValueGatewayFilterFactory
配置方式:
spring:
cloud:
gateway:
routes:
filters:
- AddResponseHeader=X-Response-Foo, Bar
2
3
4
5
6
# 8.3 核心API
- exchange.getRequest().mutate().xxx 修改request
- exchange.mutate().xxx 修改exchange
- chain.filter(exchange) 传递给下一个过滤器处理
# 8.4 编写一个过滤器工厂
进入这个过滤器的时候打印一下日志
@Slf4j
@Component
public class PreLogGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return (exchange, chain) -> {
log.info("请求进入 PreLogGatewayFilterFactory...... {} {}", config.getName(), config.getValue());
final ServerHttpRequest modifiedRequest = exchange.getRequest().mutate().build();
final ServerWebExchange modifiedExchange = exchange.mutate().request(modifiedRequest).build();
return chain.filter(modifiedExchange);
};
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
配置
spring:
cloud:
gateway:
routes:
filters:
- PreLog=a,b
2
3
4
5
6
# 九、全局过滤器
# 十、监控SpringCloudGateway
添加 Spring Boot Actuator,并将 gateway
断点暴露
management:
endpoints:
web:
exposure:
# 当然暴露'*' 更好啦..
include: gateway
2
3
4
5
6
/actuator/gateway/
ID | HTTP Method | Description |
---|---|---|
globalfilters | GET | 展示所有的全局过滤器 |
routefilters | GET | 展示所有的过滤器工厂(GatewayFilter factories) |
refresh | POST【无消息体】 | 清空路由缓存 |
routes | GET | 展示路由列表 |
routes/{id} | GET | 展示指定id的路由的信息 |
routes/{id} | POST【消息体如下】 | 新增一个路由 |
routes/{id} | DELETE【无消息体】 | 删除一个路由 |
其中,要想动态添加路由配置,只需发送POST请求,消息体如下:
{
"predicates": [
{
"name": "Path",
"args": {
"_genkey_0": "/test"
}
}
],
"filters": [
{
"name": "AddRequestHeader",
"args": {
"_genkey_0": "X-Request-Foo",
"_genkey_1": "Bar"
}
},
{
"name": "PreLog",
"args": {
"_genkey_0": "a",
"_genkey_1": "b"
}
}
],
"uri": "https://www.itmuch.com",
"order": 0
}
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
如果没有实时生效,使用refresh端点刷新一下路由信息即可。
# 十一、排错、调试技巧总结
# 第一式:Actuator监控端点
借助Actuator的监控端点,可分析全局过滤器、过滤器工厂、路由详情。详见:Spring Cloud Gateway监控 (opens new window)
# 第二式:日志
加日志,按需将如下包的日志级别设置成 debug
或 trace
,总有一款对你有用。
org.springframework.cloud.gateway
org.springframework.http.server.reactive
org.springframework.web.reactive
org.springframework.boot.autoconfigure.web
reactor.netty
redisratelimiter
配置示例:
logging:
level:
org.springframework.cloud.gateway: trace
2
3
# 第三式:Wiretap【从Greenwich SR3及更高版本才会支持】
Reactor Netty HttpClient
以及 HttpServer
可启用 Wiretap
。将reactor.netty
包设置成 debug
或 trace
,然后设置如下属性:
spring.cloud.gateway.httpserver.wiretap=true
spring.cloud.gateway.httpclient.wiretap=true
分别开启HttpServer及HttpClient的Wiretap。
然后,就可以分析日志啦。
# 十二、过滤器执行顺序
- Order越小越先执行
- 局部过滤器的Order按照配置的顺序从1开始递增
- 如果配置了全局过滤器(default-filters),则先执行相同Order的默认过滤器
- 如需自行控制Order,可以返回OrderGatewayFilter
# 十三、Spring Cloud Gateway限流
- 一、为什么要使用网关
- 三、架构剖析
- 三、编写SpringCloudGateway
- 3.1 添加依赖
- 3.2 编写配置
- 3.3 启动项目并测试
- 3.4 转发规律
- 四、核心概念
- Route(路由)
- Predicate(断言)
- Filter(过滤器)
- 🧐 路由配置示例
- 五、内置路由断言工厂详解(RoutePredicateFactories)
- 六、自定义路由断言工厂(假设服务只有9:00 ~ 17:00才可以访问)
- 6.1 创建一个自定义路由断言工厂
- 6.2 添加配置
- 6.3 时间配置补充:
- 6.4 测试
- 七、内置过滤器工厂
- 八、自定义过滤器工厂
- 8.1 生命周期
- 8.2 自定义过滤器工厂的方式
- 8.3 核心API
- 8.4 编写一个过滤器工厂
- 九、全局过滤器
- 十、监控SpringCloudGateway
- 十一、排错、调试技巧总结
- 第一式:Actuator监控端点
- 第二式:日志
- 第三式:Wiretap【从Greenwich SR3及更高版本才会支持】
- 十二、过滤器执行顺序
- 十三、Spring Cloud Gateway限流