在SpringCloud中使用网关过滤器
1.自定义全局过滤器GlobalFilter
全局过滤器,应用在所有路由上的过滤器。在开发中也是最常用GlobalFilter的
自定义GlobalFilter只需要实现GlobalFilter接口就好,如果你还需要定义过滤器的优先级的话就在实现一个Ordered接口就可以 数字越小优先级越高
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//模拟登录校验逻辑
HttpHeaders headers = exchange.getRequest().getHeaders();
// 编写过滤器逻辑
System.out.println("从网关过滤器中获取到的请求的AUTHORIZATION为:"+headers.get(HttpHeaders.AUTHORIZATION));
// 放行
return chain.filter(exchange);
}
/*定义过滤器的优先级*/
@Override
public int getOrder() {
return 0;
}
}
其中,ServerWebExchange 类,是一个客户端请求和服务端响应的对象,相当于一个上下文,里面包好了请求方法,请求路径,请求头,请求体等信息,并提供了获取这些信息的方法。
GateWayFilterChain 是一个过滤链对象, 对象中包含了一系列过滤链,并提供了把请求传递给下一个过滤链的方法
return chain.filter(exchange); 就是把请求信息传递给下一个过滤链了
如何将请求获取到的上下文对象的信息 传递给微服务呢?
既然exchange 是一个客户端请求和服务端响应的ServerWebExchange 对象,而且最后我们可以通过GateWayFilterChain 过滤链对象,把ServerWebExchange 对象传递给下一个过滤链,那么我们就可以改变exchange里的信息(比如请求方法,请求路径,请求头,请求体....)
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//获取到Request对象
ServerHttpRequest request = exchange.getRequest();
//在Request对象中获取到前端传入的token
......
//解析toke获得userId
.....
//把userId放入交换对象,传给下一个过滤链
ServerWebExchange exchange=exchange.mutate()
.request(builder -> builder.header("user-Info", userInfo))
.build();
return chain.filter(exchange);
}
/*定义过滤器的优先级*/
@Override
public int getOrder() {
return 0;
}
}
exchange.mutate() 方法是在原来传入的exchange对象基础上做修改,返回一个新的对象
2.自定义局部过滤器GatewayFilter
路由过滤器,作用范围比较灵活,可以是任意指定的路由
Route
自定义GatewayFilter
不是直接实现GatewayFilter
,而是实现AbstractGatewayFilterFactory
。最简单的方式是这样的:
@Component
public class PrintAnyGatewayFilterFactory extends AbstractGatewayFilterFactory<Object> {
@Override
public GatewayFilter apply(Object config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获取请求
ServerHttpRequest request = exchange.getRequest();
// 编写过滤器逻辑
System.out.println("过滤器执行了");
// 放行
return chain.filter(exchange);
}
};
}
}
注意:该类的名称一定要以GatewayFilterFactory
为后缀!
然后在yaml配置中这样使用:
spring:
cloud:
gateway:
default-filters:
- PrintAny # 此处直接以自定义的GatewayFilterFactory类名称前缀类声明过滤器
另外,这种过滤器还可以支持动态配置参数,不过实现起来比较复杂,示例:
@Component
public class PrintAnyGatewayFilterFactory // 父类泛型是内部类的Config类型
extends AbstractGatewayFilterFactory<PrintAnyGatewayFilterFactory.Config> {
@Override
public GatewayFilter apply(Config config) {
// OrderedGatewayFilter是GatewayFilter的子类,包含两个参数:
// - GatewayFilter:过滤器
// - int order值:值越小,过滤器执行优先级越高
return new OrderedGatewayFilter(new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获取config值
String a = config.getA();
String b = config.getB();
String c = config.getC();
// 编写过滤器逻辑
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("c = " + c);
// 放行
return chain.filter(exchange);
}
}, 100);
}
// 自定义配置属性,成员变量名称很重要,下面会用到
@Data
static class Config{
private String a;
private String b;
private String c;
}
// 将变量名称依次返回,顺序很重要,将来读取参数时需要按顺序获取
@Override
public List<String> shortcutFieldOrder() {
return List.of("a", "b", "c");
}
// 返回当前配置类的类型,也就是内部的Config
@Override
public Class<Config> getConfigClass() {
return Config.class;
}
}
然后在yaml文件中使用:
spring:
cloud:
gateway:
default-filters:
- PrintAny=1,2,3 # 注意,这里多个参数以","隔开,将来会按照shortcutFieldOrder()方法返回的参数顺序依次复制
上面这种配置方式参数必须严格按照shortcutFieldOrder()方法的返回参数名顺序来赋值。
还有一种用法,无需按照这个顺序,就是手动指定参数名:
spring:
cloud:
gateway:
default-filters:
- name: PrintAny
args: # 手动指定参数名,无需按照参数顺序
a: 1
b: 2
c: 3