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

文章作者: 落叶知秋
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 落叶知秋
学习笔记
喜欢就支持一下吧