• 009-spring cloud gateway-过滤器GatewayFilter、GlobalFilter、GatewayFilterChain、作用、生命周期、GatewayFilterFactory内置过滤器


    一、概述

      在Spring-Cloud-Gateway之请求处理流程中最终网关是将请求交给过滤器链表进行处理。

      核心接口:GatewayFilter,GlobalFilter,GatewayFilterChain。

    查看整体类图

      

    二、网关过滤器作用

      

      当使用微服务构建整个 API 服务时,一般有许多不同的应用在运行,如上图所示的mst-user-servicemst-good-servicemst-order-service,这些服务都需要对客户端的请求的进行 Authentication。最简单粗暴的方法就是像上图一样,为每个微服务应用都实现一套用于校验的过滤器或拦截器。

      通过前置的网关服务来完成这些非业务性质的校验。

      

    三、Filter 的生命周期

      Spring Cloud Gateway 的 Filter 的生命周期有两个:“pre” 和 “post”。

      

      “pre”和 “post” 分别会在请求被执行前调用和被执行后调用,和 Zuul Filter 或 Spring Interceptor 中相关生命周期类似,但在形式上有些不一样。

      Zuul 的 Filter 是通过filterType()方法来指定,一个 Filter 只能对应一种类型,要么是 “pre” 要么是“post”。Spring Interceptor 是通过重写HandlerInterceptor中的三个方法来实现的。而 Spring Cloud Gateway 基于 Project Reactor 和 WebFlux,采用响应式编程风格,打开它的 Filter 的接口GatewayFilter你会发现它只有一个方法filter

    四、核心接口解读

    4.1、GatewayFilterChain--网关过滤链表

    /**
     * 网关过滤链表接口
     * 用于过滤器的链式调用
     */
    public interface GatewayFilterChain {
    
        /**
         *  链表启动调用入口方法*/
        Mono<Void> filter(ServerWebExchange exchange);
    
    }

    默认实现

      /**
         * 网关过滤的链表,用于过滤器的链式调用
         * 过滤器链表接口的默认实现,
         * 包含2个构建函数:
         *  1.集合参数构建用于初始化吧构建链表
         *  2. index,parent参数用于构建当前执行过滤对应的下次执行的链表 
         */
        private static class DefaultGatewayFilterChain implements GatewayFilterChain {
    
            /**
             * 当前过滤执行过滤器在集合中索引
             */
            private final int index;
            /**
             * 过滤器集合
             */
            private final List<GatewayFilter> filters;
    
            public DefaultGatewayFilterChain(List<GatewayFilter> filters) {
                this.filters = filters;
                this.index = 0;
            }
    
            /**
             * 构建
             * @param parent 上一个执行过滤器对应的FilterChain
             * @param index  当前要执行过滤器的索引
             */
            private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) {
                this.filters = parent.getFilters();
                this.index = index;
            }
    
            public List<GatewayFilter> getFilters() {
                return filters;
            }
    
            /**
             * @param exchange the current server exchange
             * @return
             */
            @Override
            public Mono<Void> filter(ServerWebExchange exchange) {
                return Mono.defer(() -> {
                    if (this.index < filters.size()) {
                        //获取当前索引的过滤器
                        GatewayFilter filter = filters.get(this.index);
                        //构建当前索引的下一个过滤器的FilterChain
                        DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1);
                        //调用过滤器的filter方法执行过滤器
                        return filter.filter(exchange, chain);
                    } else {
                        //当前索引大于等于过滤集合大小,标识所有链表都已执行完毕,返回空
                        return Mono.empty(); // complete
                    }
                });
            }
        }

    过滤器的GatewayFilterChain 执行顺序

    1. 通过GatewayFilter集合构建顶层的GatewayFilterChain
    2. 调用顶层GatewayFilterChain,获取第一个Filter,并创建下一个Filter索引对应的GatewayFilterChain
    3. 调用filter的filter方法执行当前filter,并将下次要执行的filter对应GatewayFilterChain传入。

    4.2、GatewayFilter--网关路由过滤器

    /**
     * 网关路由过滤器,
     * Contract for interception-style, chained processing of Web requests that may
     * be used to implement cross-cutting, application-agnostic requirements such
     * as security, timeouts, and others. Specific to a Gateway
     *
     */
    public interface GatewayFilter extends ShortcutConfigurable {
    
        String NAME_KEY = "name";
        String VALUE_KEY = "value";
    
        /**
         *  过滤器执行方法
         * Process the Web request and (optionally) delegate to the next
         * {@code WebFilter} through the given {@link GatewayFilterChain}.
         * @param exchange the current server exchange
         * @param chain provides a way to delegate to the next filter
         * @return {@code Mono<Void>} to indicate when request processing is complete
         */
        Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
    
    }

    网关过滤器接口,有且只有一个方法filter,执行当前过滤器,并在此方法中决定过滤器链表是否继续往下执行。

    1️⃣、OrderedGatewayFilter--排序

    /**
     * 排序的网关路由过滤器,用于包装真实的网关过滤器,已达到过滤器可排序
     */
    public class OrderedGatewayFilter implements GatewayFilter, Ordered {
    
        //目标过滤器
        private final GatewayFilter delegate;
        //排序字段
        private final int order;
    
        public OrderedGatewayFilter(GatewayFilter delegate, int order) {
            this.delegate = delegate;
            this.order = order;
        }
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            return this.delegate.filter(exchange, chain);
        }
    }

    OrderedGatewayFilter实现类主要目的是为了将目标过滤器包装成可排序的对象类型。是目标过滤器的包装类

    2️⃣、GatewayFilterAdapter

      /**
         * 全局过滤器的包装类,将全局路由包装成统一的网关过滤器
         */
        private static class GatewayFilterAdapter implements GatewayFilter {
    
            /**
             * 全局过滤器
             */
            private final GlobalFilter delegate;
    
            public GatewayFilterAdapter(GlobalFilter delegate) {
                this.delegate = delegate;
            }
    
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                return this.delegate.filter(exchange, chain);
            }
        }

    GatewayFilterAdapter实现类主要目的是为了将GlobalFilter过滤器包装成GatewayFilter类型的对应。是GlobalFilter过滤器的包装类

    4.3、GlobalFilter

      

      GlobalFilter 为请求业务以及路由的URI转换为真实业务服务的请求地址的核心过滤器,不需要配置,模式系统初始化时加载,并作用在每个路由上

    1️⃣、初始化加载,通过GatewayAutoConfiguration自动创建

    //GatewayAutoConfiguration 类
            /**
             * 全局过滤器,用户通过HttpClient转发请求
             */
            @Bean
            public NettyRoutingFilter routingFilter(HttpClient httpClient,
                                                    ObjectProvider<List<HttpHeadersFilter>> headersFilters) {
                return new NettyRoutingFilter(httpClient, headersFilters);
            }
    
            /**
             * 全局的过滤器,用户将HttpClient客户端转发请求的响应写入到原始的请求响应中
             */
            @Bean
            public NettyWriteResponseFilter nettyWriteResponseFilter(GatewayProperties properties) {
                return new NettyWriteResponseFilter(properties.getStreamingMediaTypes());
            }
            
    //GatewayLoadBalancerClientAutoConfiguration 类
        /**
         * 全局过滤器,用于在通过负载均衡客户端选择服务实例信息
         */
        @Bean
        @ConditionalOnBean(LoadBalancerClient.class)
        public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client) {
            return new LoadBalancerClientFilter(client);
        }

    2️⃣、GlobalFilter转换成GatewayFilter,并作用于每个路由上,在FilteringWebHandler实现

    //FilteringWebHandler类
        /**
         * 包装加载全局的过滤器,将全局过滤器包装成GatewayFilter
         */
        private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
            return filters.stream()
                    .map(filter -> {
                        //将所有的全局过滤器包装成网关过滤器
                        GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
                        //判断全局过滤器是否实现了可排序接口
                        if (filter instanceof Ordered) {
                            int order = ((Ordered) filter).getOrder();
                            //包装成可排序的网关过滤器
                            return new OrderedGatewayFilter(gatewayFilter, order);
                        }
                        return gatewayFilter;
                    }).collect(Collectors.toList());
        }
        @Override
        public Mono<Void> handle(ServerWebExchange exchange) {
            //获取请求上下文设置的路由实例
            Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
            //获取路由定义下的网关过滤器集合
            List<GatewayFilter> gatewayFilters = route.getFilters();
    
            //组合全局的过滤器与路由配置的过滤器
            List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
            //添加路由配置过滤器到集合尾部
            combined.addAll(gatewayFilters);
            //对过滤器进行排序
            //TODO: needed or cached?
            AnnotationAwareOrderComparator.sort(combined);
    
            logger.debug("Sorted gatewayFilterFactories: "+ combined);
            //创建过滤器链表对其进行链式调用
            return new DefaultGatewayFilterChain(combined).filter(exchange);
        }
    • loadFilters方法是将全局路由使用GatewayFilterAdapter包装成GatewayFilter
    • handle方法
      • 获取当前请求使用的路由Route
      • 获取路由配置的过滤器集合route.getFilters()
      • 合并全过滤器与路由配置过滤器combined
      • 对过滤器排序AnnotationAwareOrderComparator.sort
      • 通过过滤器集合构建顶级链表DefaultGatewayFilterChain,并对其当前请求调用链表的filter方法。
    小结

    Spring-Cloud-Gateway的过滤器接口分为两种:

    1. GlobalFilter : 全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器
    2. GatewayFilter : 需要通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过spring.cloud.default-filters配置在全局,作用在所有路由上

    五、GatewayFilterFactory 配置路由过滤器

      路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路径过滤器的范围限定为特定路径。 

    1️⃣、加载GatewayFilter

      在路由定位器中以及看到了通过路由定义转换路由方法,其中包含了通过过滤器定义(FilterDefinition)转换过滤器(GatewayFilter)的部分,在RouteDefinitionRouteLocator类中源码如下:

    /**
         * 加载过滤器,根据过滤器的定义加载
         */
        @SuppressWarnings("unchecked")
        private List<GatewayFilter> loadGatewayFilters(String id, List<FilterDefinition> filterDefinitions) {
            //遍历过滤器定义,将过滤器定义转换成对应的过滤器
            List<GatewayFilter> filters = filterDefinitions.stream()
                    .map(definition -> {
                        //通过过滤器定义名称获取过滤器创建工厂
                        GatewayFilterFactory factory = this.gatewayFilterFactories.get(definition.getName());
                        if (factory == null) {
                            throw new IllegalArgumentException("Unable to find GatewayFilterFactory with name " + definition.getName());
                        }
                        //获取参数
                        Map<String, String> args = definition.getArgs();
                        if (logger.isDebugEnabled()) {
                            logger.debug("RouteDefinition " + id + " applying filter " + args + " to " + definition.getName());
                        }
    
                        //根据args组装配置信息
                        Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory);
                        //构建过滤器创建配置信息
                        Object configuration = factory.newConfig();
                        ConfigurationUtils.bind(configuration, properties,
                                factory.shortcutFieldPrefix(), definition.getName(), validator);
    
                        //通过过滤器工厂创建GatewayFilter
                        GatewayFilter gatewayFilter = factory.apply(configuration);
                        if (this.publisher != null) {
                            //发布事件
                            this.publisher.publishEvent(new FilterArgsEvent(this, id, properties));
                        }
                        return gatewayFilter;
                    })
                    .collect(Collectors.toList());
    
            ArrayList<GatewayFilter> ordered = new ArrayList<>(filters.size());
            //包装过滤器使其所有过滤器继承Ordered属性,可进行排序
            for (int i = 0; i < filters.size(); i++) {
                GatewayFilter gatewayFilter = filters.get(i);
                if (gatewayFilter instanceof Ordered) {
                    ordered.add(gatewayFilter);
                }
                else {
                    ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
                }
            }
    
            return ordered;
        }
    
        /**
         * 获取RouteDefinition中的过滤器集合
         */
        private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {
            List<GatewayFilter> filters = new ArrayList<>();
    
            //校验gatewayProperties是否含义默认的过滤器集合
            //TODO: support option to apply defaults after route specific filters?
            if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
                //加载全局配置的默认过滤器集合
                filters.addAll(loadGatewayFilters("defaultFilters",
                        this.gatewayProperties.getDefaultFilters()));
            }
    
            if (!routeDefinition.getFilters().isEmpty()) {
                //加载路由定义中的过滤器集合
                filters.addAll(loadGatewayFilters(routeDefinition.getId(), routeDefinition.getFilters()));
            }
    
            //排序
            AnnotationAwareOrderComparator.sort(filters);
            return filters;
        }
    • getFilters方法 合并配置中的全局过滤器与路由自身配置的过滤器,并对其排序(全局配置过滤器信息通过gatewayProperties.getDefaultFilters()获取)
    • loadGatewayFilters 依次遍历路由定义下的FilterDefinition并将其通过对应的GatewayFilterFactory转换为GatewayFilter对象。
    2️⃣、GatewayFilterFactory配置过滤器创建工厂创建GatewayFilter对象
      默认内置很多GatewayFilterFactory实现类,用于创建作用不同的网关过滤器。
    类图
      

    子类及其划分

    3️⃣、AddResponseHeaderGatewayFilterFactory 创建解析

    /**
     *
     * 响应header添加数据过滤器
     * 用户在response header中添加配置数据
     */
    public class AddResponseHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
    
        @Override
        public GatewayFilter apply(NameValueConfig config) {
            return (exchange, chain) -> {
                //获取Response并将配置的数据添加到header中
                exchange.getResponse().getHeaders().add(config.getName(), config.getValue());
    
                return chain.filter(exchange);
            };
        }
    }。

    配置示例:

    spring:
      cloud:
        gateway:
          default-filters:
          - AddResponseHeader=X-Response-Default-Foo, Default-Bar
    • AddResponseHeader=X-Response-Default-Foo, Default-Bar 会被解析成FilterDefinition对象 (name =AddResponseHeader ,args= [X-Response-Default-Foo,Default-Bar])
    • 通FilterDefinition的Name找到AddResponseHeaderGatewayFilterFactory工厂
    • 通过FilterDefinition 的args 创建Config对象(name=X-Response-Default-Foo,value=Default-Bar)
    • 通过 AddResponseHeaderGatewayFilterFactory工厂的apply方法传入config创建GatewayFilter对象。

    4️⃣、全部配置

    5.1、请求头

    spring:
      cloud:
        gateway:
          routes:
          - id: add_request_header_route
            uri: http://example.org
            filters:
            - AddRequestHeader=X-Request-Foo, Bar

    名称和值,这将为所有匹配请求的下游请求标头添加X-Request-Foo:Bar标头。

    移除请求头

            filters:
            - RemoveRequestHeader=X-Request-Foo

    5.2、请求参数

            filters:
            - AddRequestParameter=foo, bar

    这会将foo = bar添加到下游请求的所有匹配请求的查询字符串中。

    5.3、添加响应头

            filters:
            - AddResponseHeader=X-Response-Foo, Bar

    这会将X-Response-Foo:Bar标头添加到所有匹配请求的下游响应标头中。

    移除响应头

            filters:
            - RemoveResponseHeader=X-Response-Foo

    设置响应头

            filters:
            - SetResponseHeader=X-Response-Foo, Bar

    此GatewayFilter将替换具有给定名称的所有标头,而不是添加。

    5.4、路径前缀

            filters:
            - PrefixPath=/mypath

    这将使/ mypath前缀为所有匹配请求的路径。所以对/ hello的请求会被发送到/ mypath / hello。

    5.5、原始主机头

    没有参数,此过滤器设置路由过滤器将检查的请求属性,以确定是否应发送原始主机头,而不是http客户端确定的主机头。

            filters:
            - PreserveHostHeader

    5.6、重定向

            filters:
            - RedirectTo=302, http://acme.org

    这将发送带有Location:http://acme.org标头的状态302以执行重定向。

    5.7、重写路径

            predicates:
            - Path=/foo/**
            filters:
            - RewritePath=/foo/(?<segment>.*), /${segment}

    对于/ foo / bar的请求路径,这将在发出下游请求之前将路径设置为/ bar。注意由于YAML规范,$ 替换为$。

    5.8、保存Session

            predicates:
            - Path=/foo/**
            filters:
            - SaveSession

    5.9、路径模板

    SetPath GatewayFilter Factory采用路径模板参数。它提供了一种通过允许模板化路径段来操作请求路径的简单方法。

            predicates:
            - Path=/foo/{segment}
            filters:
            - SetPath=/{segment}

    对于/ foo / bar的请求路径,这将在发出下游请求之前将路径设置为/ bar。

    5.10、设置响应状态

    spring:
      cloud:
        gateway:
          routes:
          - id: setstatusstring_route
            uri: http://example.org
            filters:
            - SetStatus=BAD_REQUEST
          - id: setstatusint_route
            uri: http://example.org
            filters:
            - SetStatus=401

    5.11、请求参数剥离

    parts参数指示在将请求发送到下游之前从请求中剥离的路径中的部分数。

            predicates:
            - Path=/name/**
            filters:
            - StripPrefix=2

    当通过网关向/ name / bar / foo发出请求时,对nameservice的请求将类似于http:// nameservice / foo。

    5.12、重试

    retries:重试:应该尝试的重试次数

    statuses:状态:应该重试的HTTP状态代码,使用org.springframework.http.HttpStatus表示

    methods:方法:应该重试的HTTP方法,使用org.springframework.http.HttpMethod表示

    series:系列:要重试的状态代码系列,使用org.springframework.http.HttpStatus.Series表示

          routes:
          - id: retry_test
            uri: http://localhost:8080/flakey
            predicates:
            - Host=*.retry.com
            filters:
            - name: Retry
              args:
                retries: 3
                statuses: BAD_GATEWAY

    5.13、Hystrix GatewayFilter Factory

    https://cloud.spring.io/spring-cloud-static/Finchley.SR1/single/spring-cloud.html#_hystrix_gatewayfilter_factory

    5.14、请求限速 

      RequestRateLimiter GatewayFilter Factory

    5.15、安全头

      SecureHeaders GatewayFilter Factory

      
  • 相关阅读:
    中毒了
    【工具】Intel HLS工具介绍
    【教程】OpenVINO 入门
    【教程】RISCV 处理器入门 在Intel FPGA 上的设计与实现 零基础 手把手教程
    多进程任务状态原理
    汇编指令集合大全 收藏
    教你如何用PQ魔法师调整硬盘分区大小【图解教程】
    8259A初始化编程
    eflags 详解
    网络分析 论坛
  • 原文地址:https://www.cnblogs.com/bjlhx/p/9786478.html
Copyright © 2020-2023  润新知