目录
6.2.1:After、before、Between时间日期匹配
1:什么是GateWay
Spring Cloud Gateway 是 Spring Cloud 新推出的网关框架,之前是 Netflix Zuul1,Gateway比 Zuul 2 更早的使用 Netty 实现异步 IO,从而实现了一个简单、比 Zuul 1.x 更高效的、与 Spring Cloud 紧密配合的 API 网关。
参考spring官网:Spring Cloud Gateway
警告:Spring Cloud Gateway需要Spring Boot和Spring Webflux提供的Netty运行时。它不能在传统的Servlet容器中(比如tomcat)工作,也不能作为WAR构建。
2:网关的作用
在微服务之前对访问进行路径管理,屏蔽原始地址,统一访问网关地址,网关再根据配置的过滤条件决定是否访问地址。业务在网关中统一进行权限、安全、路由等管理。Spring Cloud Gateway旨在提供一种简单而有效的方法来路由到API,并为它们提供跨领域的关注点,如:安全性、监控/度量和弹性。
春季云网关功能:
-
基于Spring Framework和Spring Boot构建
-
能够匹配任何请求属性的路由。(Gateway根据路径规则,发送到不同的微服务)
-
谓詞和过滤器是特定于路线的。 (Gateway根据路径规则,发送到不同的微服务)
-
断路器集成。
-
Spring Cloud DiscoveryClient集成
-
易于编写谓詞和过滤器
-
请求速率限制
-
路径重写
3:Nginx和GateWay对比
3.1:对比说明
相同点:都是可以实现对api接口的拦截,负载均衡、反向代理、请求过滤等。
不同点:Nginx是用C语言写的效率更高,而Gateway是用Java写的,能够更好对微服务实现拓展功能,而Nginx想要实现拓展功能需要结合Lua语言等。此外Nginx实现负载均衡原理是属于服务器端负载均衡器,是内网和外网的界限。而Gateway则是采用本地负载均衡的形式。
3.2:详细说明
3.2.1:Nginx的作用
案例说明:Nginx作用大讲解,Nginx是外网和内网的分界,用来隐藏内网的地址。
有这么一个需求,后端服务器是个大单体,功能都一样,启动了6个,这个大单体里边有支付服务(pay的请求路径)、下单服务(Order的请求路径)都会路由到后端的6个大单体中。这就是没使用微服务的GateWay之前
http://localhost:8080/pay/1 (模拟支付服务)
http://localhost:8080/order/1 (模拟下单服务)
无论我们访问支付服务、下单服务都会被nginx给路由的后端的91-96服务
这就是传统的Nginx服务,将外网的用户请求,代理负载到内网
3.2.2:GateWay的作用
案例说明:Gate网关决定进入根据判定到哪个真实的web 服务器,主要处理内网之间的调用
在传统的大单体服务中,代码越来越多,维护越来越困难。(这里不站队微服务和大单体选择)。我们说一个情况,我们对服务进行了拆分,支付服务和下单服务拆分了出来。做成了微服务。主服务、下单服务、支付服务个启动了3个,一共九个
现在有三种请求
1:主服务微服务请求(任意路径) http://localhost:8071/xxx/** 3个服务端口是71-73
2:支付微服务请求(pay路径) http://localhost:8081/pay/1 3个服务端口是81-83
3:下单微服务请求(order路径) http://localhost:8091/order/1 3个服务端口是91-93
业务是主服务会调用支付、下单服务。
如果通过前边的ngxin,作为开发者是否要部署3个Nginx来分别为主服务集群、支付服务集群、下单服务集群做代理呢?
显然不合适?那么怎么做,我们在nginx后边启动GateWay作为服务的业务分路由。让GateWay根据请求的路径,比如说路径含有pay的,自动发送的支付的为服务集群上。路径含有order的,自动发送的下单的微服务集群上。其他的发送到主服务集群上。这是怎么实现的呢?我们接着往下看
(网关的作用很多,这里就是主要的作用)
4:GateWay特点
Route: 路由(网关的基本构造块,有id、url、谓语、过滤器组成,用来匹配请求)
Predicate:谓语(这允许您匹配HTTP请求中的任何内容,例如标头或参数。)
Filter:过滤器(您可以在发送下游请求之前或之后修改请求和响应。)
客户端向 Spring Cloud Gateway 发出请求。如果 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。
过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。
5:GateWay创建
5.1:创建一个网关的服务9257
1:导入pom
<properties>
<java.version>17</java.version>
<spring-cloud.version>2023.0.3</spring-cloud.version>
</properties>
<dependencies>
<!-- 导入GateWay依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--导入consul的依赖 consul版本是4.1.2-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--springboot的健康监控,springCloud依赖这个监控,来发送心跳-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2:配置yml
#这只是一个网关的服务,注册到consul上
server:
port: 9527
spring:
application:
name: Consumer3_GateWay
cloud: #网关服务的consul服务注册,服务名字是:Consumer3_GateWay
consul:
port: 8500 #consul地址
host: localhost
discovery:
service-name: ${spring.application.name} #网关服务名字
prefer-ip-address: true #优先使用ip注册
gateway: #开启路由
discovery:
locator:
enabled: true
routes: #路由规则配置 包含id url 谓语
- id: routes1 #路由id,主键唯一
uri: lb://PayService #负载均衡路由的微服务地址,这是一个支付微服务可以到91、92
predicates:
- Path=/pay/getWay/get/** #断言,对路径进行匹配的进行路由,带pay的路径匹配到支付微服务
- id: routes2 #路由id
uri: http://localhost:8091 #路由的微服务地址 这里控制变量,只会请求91
predicates:
- Path=/pay/getWay/info/** #断言,对路径进行匹配的进行路由 到91
- id: routes3 #路由id,主键唯一
uri: lb://OrderService #路由的微服务地址,这是一个订单微服务
predicates:
- Path=/pay/getWay/info/** #断言,对路径进行匹配的进行路由
3:启动9257
//Gateway网关服务,没有业务代码,只是网关,直接启动
@SpringBootApplication
@EnableDiscoveryClient //服务注册到consul
public class Consumer3GateWayApplication9527 {
public static void main(String[] args) {
SpringApplication.run(Consumer3GateWayApplication9527.class, args);
}
}
4:consul查看网关服务
5.2: 支付微服务的代码8091、8092一致
@RestController
public class PayGateWayController {
@Resource
TPayService tPayService;
@GetMapping(value = "/pay/getWay/info")
public ResultData<Object> get(HttpServletRequest request){
System.out.println("Pay网关测试info"+request.getServerPort()+":"+ IdUtil.simpleUUID());
return ResultData.success("Pay网关测试"+request.getServerPort()+":"+ IdUtil.simpleUUID());
}
@GetMapping(value = "/pay/getWay/get/{id}")
@Operation(summary = "根据id查询", description = "参数是id")
public ResultData<Object> getById(@PathVariable("id") Integer id,HttpServletRequest request) {
System.out.println("Pay网关测试get:"+request.getServerPort()+":"+ IdUtil.simpleUUID());
TPay byId = tPayService.getById(id);
if (byId == null) {
return ResultData.fail(ReturnCodeEnum.RC999.getCode(), "根据id查询数据不存在!");
}else {
return ResultData.success(byId);
}
}
}
5.2:服务验证
Nginx(9090)-------->网关服务(9527)--------->支付微服务8091、8092
截图证明:
访问Nginx地址:http://localhost:9090/pay/getWay/get/1
可以点击两次在控制台查看8091、8092都查询日志。
========================================================
访问Nginx地址:http://localhost:9090/pay/getWay/info
6:网关功能详解
6.1:路由(Route)
路由(Router):网关的基本构建块。它由ID、目标URI、谓词集合和过滤器集合定义。如果聚合谓词为真,则匹配路线。
截图显示:在上面的第四条,网关9527把经过他的请求,根据路径匹配到支付模块8091、8092
6.2:断言(Predicate)
断言(Predicate):这是一个Java 8函数谓詞。输入类型是Spring Framework ServerWebExchange。这允许您匹配HTTP请求中的任何内容,例如标头或参数。说人话就是根据http请求,根据请求路径,参数,请求头。来判断请求要经过网关发送到哪里。是各种的条件判断,下边举例说明,在官网中支持10多种条件判断,详情见官网。
断言只能匹配已知的规则,不能修改http请求和响应的规则。
这就是gateWay比nginx功能路由强大的地方,可以在url之后根据断言,做各种的请求过滤,定位也不一样,作为Nginx的后置。
下边图片就是汉化版的详细功能介绍:
详细案例
6.2.1:After、before、Between时间日期匹配
After
路由谓词工厂需要一个参数,即datetime
(即java ZonedDateTime
)。此谓词匹配在指定日期和时间之后发生的请求。以下示例配置了路由后谓词:
适用于秒杀请求,到点才能访问:
routes: #路由规则配置 包含id url 谓语
- id: routes2 #路由id,路径匹配,只会发送到8091
uri: http://localhost:8091 #路由的微服务地址 这里控制变量,只会请求91
predicates:
#After 在这个日期之后才能访问
- After=2024-09-29T21:07:33.385537+08:00[Asia/Shanghai]
#Before 在这个日期之前才能访问
- Before=2024-09-30T21:11:59.385537+08:00[Asia/Shanghai]
#Between 在这个日期之间才能访问,有了between 就不需要之前、之后了
- Between=2024-09-29T21:07:33.385537+08:00[Asia/Shanghai],2024-09-29T21:10:59.385537+08:00[Asia/Shanghai]
- Path=/pay/getWay/info/** #断言,对路径进行匹配的进行路由 到91
6.2.2:Cookie匹配
Cookie
路由谓词工厂需要两个参数,即cookiename
和regexp
(Java正则表达式)。此谓词匹配具有给定名称且其值与正则表达式匹配的cookie。以下示例配置了cookie路由谓词工厂:
- id: routes2 #路由id,路径匹配,只会发送到8091
uri: http://localhost:8091 #路由的微服务地址 这里控制变量,只会请求91
predicates:
#After 在这个日期之后才能访问
#- After=2024-09-29T21:07:33.385537+08:00[Asia/Shanghai]
#Before 在这个日期之前才能访问
#- Before=2024-09-30T21:11:59.385537+08:00[Asia/Shanghai]
#Between 在这个日期之间才能访问
- Between=2024-09-29T21:07:33.385537+08:00[Asia/Shanghai],2024-09-30T21:10:59.385537+08:00[Asia/Shanghai]
- Cookie=name,jack #设置cookie的属性key=name value=jack
- Path=/pay/getWay/info/** #断言,对路径进行匹配的进行路由 到91
测试结果:
6.2.3:Header匹配
Header
路由谓词工厂需要两个参数,标header
和regexp
(Java正则表达式)。此谓词与具有给定名称的标题匹配,其值与正则表达式匹配。以下示例配置了标题路由谓词:
- id: routes2 #路由id,路径匹配,只会发送到8091
uri: http://localhost:8091 #路由的微服务地址 这里控制变量,只会请求91
predicates:
#After 在这个日期之后才能访问
#- After=2024-09-29T21:07:33.385537+08:00[Asia/Shanghai]
#Before 在这个日期之前才能访问
#- Before=2024-09-30T21:11:59.385537+08:00[Asia/Shanghai]
#Between 在这个日期之间才能访问
- Between=2024-09-29T21:07:33.385537+08:00[Asia/Shanghai],2024-09-30T21:10:59.385537+08:00[Asia/Shanghai]
- Cookie=name,jack #设置cookie的属性key=name value=jack
- Path=/pay/getWay/info/** #断言,对路径进行匹配的进行路由 到91
- Header=X-Request-Id,\d+ #请求头设置 正则整数
如果请求有一个名为X-Request-Id
的标头,其值与\d+
正则表达式匹配(即它有一个或多个数字的值),则此路由会匹配。
测试结果:
6.2.4:Host匹配
Host
路由谓词工厂需要一个参数:主机域名的额patterns
列表。用逗号分隔
- id: routes2 #路由id,路径匹配,只会发送到8091
uri: http://localhost:8091 #路由的微服务地址 这里控制变量,只会请求91
predicates:
#After 在这个日期之后才能访问
#- After=2024-09-29T21:07:33.385537+08:00[Asia/Shanghai]
#Before 在这个日期之前才能访问
#- Before=2024-09-30T21:11:59.385537+08:00[Asia/Shanghai]
#Between 在这个日期之间才能访问
- Between=2024-09-29T21:07:33.385537+08:00[Asia/Shanghai],2024-09-30T21:10:59.385537+08:00[Asia/Shanghai]
- Cookie=name,jack #设置cookie的属性key=name value=jack
- Path=/pay/getWay/info/** #断言,对路径进行匹配的进行路由 到91
- Header=X-Request-Id,\d+ #请求头设置 正则整数
- Host=**.hello.org,**.hello.com #域名设置
测试结果:
6.2.5:Path匹配
所有的案例里边都有path参数,不在单独举例
6.2.6:Query匹配也就是参数匹配
Query
路由谓词工厂需要两个参数:一个必需param
和一个可选的regexp
(这是Java正则表达式)。以下示例配置了查询路由谓词:
- id: routes2 #路由id,路径匹配,只会发送到8091
uri: http://localhost:8091 #路由的微服务地址 这里控制变量,只会请求91
predicates:
#After 在这个日期之后才能访问
#- After=2024-09-29T21:07:33.385537+08:00[Asia/Shanghai]
#Before 在这个日期之前才能访问
#- Before=2024-09-30T21:11:59.385537+08:00[Asia/Shanghai]
#Between 在这个日期之间才能访问
- Between=2024-09-29T21:07:33.385537+08:00[Asia/Shanghai],2024-09-30T21:10:59.385537+08:00[Asia/Shanghai]
- Cookie=name,jack #设置cookie的属性key=name value=jack
- Path=/pay/getWay/info/** #断言,对路径进行匹配的进行路由 到91
- Header=X-Request-Id,\d+ #请求头设置 正则整数
- Host=**.hello.org,**.hello.com #域名设置
- Query=green,111 #请求param参数设置
测试截图如下:
6.2.7:RemoteAddr匹配
RemoteAddr
路由谓词工厂需要一个sources
列表(最小大小1),这些源是CIDR符号(IPv4或IPv6)字符串,例如192.168.0.1/16
(其中192.168.0.1
是IP地址,16
是子网掩码)。以下示例配置了RemoteAddr路由谓词:
192.168.31.1/24 相当于192.168.31.0-255,不能使用localhost了
- id: routes2 #路由id,路径匹配,只会发送到8091
uri: http://localhost:8091 #路由的微服务地址 这里控制变量,只会请求91
predicates:
- RemoteAddr=192.168.31.1/24 #本机ipv4是:192.168.31.1/24 相当于192.168.31.0-255,不能使用localhost了
测试截图:
6.2.8:Method匹配
Method
路由谓詞工厂需要一个methods
参数,该参数是一个或多个参数:要匹配的HTTP方法。以下示例配置了方法路由谓词:如果请求方法是GET
或POST
,此路由将匹配。
- id: routes2 #路由id,路径匹配,只会发送到8091
uri: http://localhost:8091 #路由的微服务地址 这里控制变量,只会请求91
predicates:
#After 在这个日期之后才能访问
#- After=2024-09-29T21:07:33.385537+08:00[Asia/Shanghai]
#Before 在这个日期之前才能访问
#- Before=2024-09-30T21:11:59.385537+08:00[Asia/Shanghai]
#Between 在这个日期之间才能访问
- Between=2024-09-29T21:07:33.385537+08:00[Asia/Shanghai],2024-09-30T21:10:59.385537+08:00[Asia/Shanghai]
- Cookie=name,jack #设置cookie的属性key=name value=jack
- Path=/pay/getWay/info/** #断言,对路径进行匹配的进行路由 到91
- Header=X-Request-Id,\d+ #请求头设置 正则整数
- Host=**.hello.org,**.hello.com #域名设置
- Query=green,111 #请求param参数设置
- RemoteAddr=192.168.31.1/24 #本机ipv4是:192.168.31.1/24 相当于192.168.31.0-255,不能使用localhost了
- Method=GET,POST #请求方法匹配
测试截图:
6.2.9:自定义断言规则匹配
需求:在请求参数中添加http://locolhost:9527/pay/getWay/info?userType=gold
userType=gold,自定义规则判断请求是否能访问。
1:新增java断言规则代码
/**
* 自定义断言MyGateWayRoutePredicateFactory 继承AbstractRoutePredicateFactory 参考AfterRoutePredicateFactory等
* 自定义规则:根据userType的等级,请求不同的需求
* - MyGateWay=gold 和 http://locolhost:9527/pay/getWay/info?userType=gold
* 参数相等才能访问
*/
@Component
public class MyGateWayRoutePredicateFactory extends AbstractRoutePredicateFactory<MyGateWayRoutePredicateFactory.Config> {
//无参构造
public MyGateWayRoutePredicateFactory() {
super(MyGateWayRoutePredicateFactory.Config.class);
}
//支持快捷方式FieldOrder
public List<String> shortcutFieldOrder() {
return Collections.singletonList("userType");
}
//核心方法
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
//获取请求中的参数userType的值 http://locolhost:9527/pay/getWay/info?userType=gold
String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");
//获取yml的userType
String userType1 = config.getUserType();
if (userType.equalsIgnoreCase(userType1)) {
return true;
}
return false;
}
};
}
//内部类 配置了路由规则
@Validated
public static class Config {
@Getter
@Setter
@NotNull
private String userType;
}
}
2:添加yml配置
- id: routes2 #路由id,路径匹配,只会发送到8091
uri: http://localhost:8091 #路由的微服务地址 这里控制变量,只会请求91
predicates:
- MyGateWay=gold #自定义规则,请求参数过滤
# - name: MyGateWay
# args:
# userType: gold
3:结果截图验证
6.3:过滤器(Filter)
过滤器的作用是:断言不能修改请求或者响应只能判断,但是过滤器可以在发送下游请求之前或之后修改请求和响应。
6.3.1:过滤器类型
过滤器的功能是修改http请求或者响应的值。他的配置文件里边有filter属性
Gateway提供很多过滤器,包括全局过滤器、指定过滤器、自定义过滤器(自己编写代码,重点学习)
1、按执行顺序分
pre过滤器(前置过滤器):转发之前执行。参数校验、权限校验、流量监控、日志输出、协议转换等
post过滤器(后置过滤器):转发之后执行。响应内容、响应头的修改,日志的输出,流量监控等
2、按作用范围分
global filter:所有路由
gateway filter:指定的路由
6.3.2:指定过滤器(也是单一过滤器)
指定过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由过滤器的范围是特定路线。Spring Cloud Gateway包括许多内置的GatewayFilter工厂。详情参考管官网
6.3.2.1:请求头过滤器
在请求头head中添加、删除、修改数据
- id: routes3 #路由id,路径匹配,只会发送到8091
uri: http://localhost:8091 #请求到91
predicates:
- Path=/pay/getWay/filter/** #断言,对路径进行匹配的进行路由,带pay的路径匹配到支付微服务
filters:
- AddRequestHeader=head1,111 #添加数据 请求头
- AddRequestHeader=head2,222 #添加数据 请求头
- RemoveRequestHeader=aa #删除数据 请求头
- SetRequestHeader=bb,bbA #修改数据 请求头
6.3.2.2:请求参数过滤器
在参数中添加、删除、修改数据
- id: routes3 #路由id,路径匹配,只会发送到8091
uri: http://localhost:8091 #请求到91
predicates:
- Path=/pay/getWay/filter/** #断言,对路径进行匹配的进行路由,带pay的路径匹配到支付微服务
filters:
- AddRequestParameter=name,jack #添加数据 参数key value
- AddRequestParameter=name1,jack1 #添加数据 参数
- AddRequestParameter=age,188 #添加数据 参数
- RemoveRequestParameter=age #删除数据 参数key
- RewriteRequestParameter=name1,jack2 #修改数据 参数key value
结果展示:
6.3.2.3:响应头过滤器
responseHead的增删改
- id: routes3 #路由id,路径匹配,只会发送到8091
uri: http://localhost:8091 #请求到91
predicates:
- Path=/pay/getWay/filter/** #断言,对路径进行匹配的进行路由,带pay的路径匹配到支付微服务
filters:
#请求head设置 增删改
- AddRequestHeader=head1,111 #添加数据 请求头key value
- AddRequestHeader=head2,222 #添加数据 请求头
- RemoveRequestHeader=aa #删除数据 请求头key
- SetRequestHeader=bb,bbA #修改数据 请求头key value
#请求参数设置 增删改
- AddRequestParameter=name,jack #添加数据 参数key value
- AddRequestParameter=name1,jack1 #添加数据 参数
- AddRequestParameter=age,188 #添加数据 参数
- RemoveRequestParameter=age #删除数据 参数key
- RewriteRequestParameter=name1,jack2 #修改数据 参数key value
#响应head设置 增删改
- AddResponseHeader=return1,11 #添加key value
- AddResponseHeader=return2,22
- RemoveResponseHeader=return2 #删除key 不能删除自己add的响应头,只能删除正经服务返回的head
- SetResponseHeader=date,2020 #修改key
验证截图:
6.3.2.4:前缀、路径、重定向过滤器
前缀:
- id: routes3 #路由id,路径匹配,只会发送到8091
uri: http://localhost:8091 #请求到91
predicates:
- Path=/getWay/filter/** #断言,对路径进行匹配的进行路由,带pay的路径匹配到支付微服务
filters:
#前缀 实际路径是 PrefixPath+Path
#原来地址:http://localhost:9527/pay/getWay/filter/1
#现在地址:http://localhost:9527/getWay/filter/1
- PrefixPath=/pay
占位符:
- id: routes3 #路由id,路径匹配,只会发送到8091
uri: http://localhost:8091 #请求到91
predicates:
- Path=/aa/bb/cc/{segment} #断言,对路径进行匹配的进行路由,带pay的路径匹配到支付微服务
filters:
#占位符 生产环境后端服务不要告诉别人 更安全
#原来地址:http://localhost:9527/pay/getWay/filter/1
#现在地址:http://localhost:9527/aa/bb/cc/1
- SetPath=/pay/getWay/filter/{segment}
重定向:
- id: routes3 #路由id,路径匹配,只会发送到8091
uri: http://localhost:8091 #请求到91
predicates:
- Path=/pay/getWay/filter/{segment} #断言,对路径进行匹配的进行路由,带pay的路径匹配到支付微服务
filters:
#只要访问地址,都会带着302重定向到设置的地址
- RedirectTo=302,https://www.baidu.com/
6.3.3:全局过滤器
一个过滤器适应全部路由,要添加过滤器并将其应用于所有路由,您可以使用spring.cloud.gateway.default-filters
。此属性包含一个过滤器列表。以下列表定义了一组默认过滤器:
6.3.3.1:配置文件实现
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Red, Default-Blue
- PrefixPath=/httpbin
6.3.3.2:代码实现
全局过滤器是应用于所有的路由策略上的,不需要配置声明,写了符合条件就会生效。
一般用来验证token 或者 记录调用时间日志
/**
* 全局过滤器,实现GlobalFilter接口,和Ordered接口即可。
*/
@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("===GateWay的全局过滤器===");
ServerHttpRequest request = exchange.getRequest();
exchange.getAttributes().put("startTime", System.currentTimeMillis());
//获取token 如果不存在 不能路由
String token = request.getQueryParams().getFirst("token");
if (token == null) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.BAD_REQUEST);
return response.setComplete();
}
//并且统计服务的调用时间 日志或者数据库输出
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
Long startTime= exchange.getAttribute("startTime");//获取开始时间
if (startTime != null) {
log.info("访问接口主机host:{}",exchange.getRequest().getURI().getHost());
log.info("访问接口主机port:{}",exchange.getRequest().getURI().getPort());
log.info("访问接口主机url:{}",exchange.getRequest().getURI().getPath());
log.info("访问接口主机参数:{}",exchange.getRequest().getURI().getRawQuery());
log.info("访问接口主机耗时:{}",(System.currentTimeMillis()-startTime)+"毫秒");
log.info("访问接口主机分割线:{}","=================");
}
}));
}
//数字越小 优先级越高
@Override
public int getOrder() {
return 0;
}
}
6.3.4:自定义过滤器
自定义过滤器,使用指定的路由
代码:
/**
* 自定义过滤器
* 在参数中匹配filter1 有这个参数才能执行
*/
@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {
public MyGatewayFilterFactory() {
super(MyGatewayFilterFactory.Config.class);
}
public List<String> shortcutFieldOrder() {
List<String> list = new ArrayList<String>();
list.add("status");
return list;
}
@Override
public GatewayFilter apply(MyGatewayFilterFactory.Config config) {
// final UriTemplate uriTemplate = new UriTemplate(config.status);
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request= exchange.getRequest();
System.out.println("获取自定义过滤器的status:"+config.getStatus());
//获取请求参数中的filer1
if (request.getQueryParams().containsKey("filter1")){
return chain.filter(exchange);
}else {
exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
return exchange.getResponse().setComplete();
}
}
};
}
public static class Config {
@Getter
@Setter
private String status; //状态值匹配才能访问
}
}
配置:
- id: routes3 #路由id,路径匹配,只会发送到8091
uri: http://localhost:8091 #请求到91
predicates:
- Path=/pay/getWay/filter/{segment} #断言,对路径进行匹配的进行路由,带pay的路径匹配到支付微服务
filters:
- My=filter1
验证: