美文网首页
spring cloud gateway中內置predicate

spring cloud gateway中內置predicate

作者: virtual灬zzZ | 来源:发表于2021-10-29 01:02 被阅读0次

    spring cloud gateway中內置predicate、filter的使用,可以參考以下链接:

    各种内置predicate、filter的使用

    自定义filter、全局filter

    先说全局filter,它是应用在所有的route的,看源码就知道,一个route的filter = 自身配的filter + defaultFilter + globalFilter。另外提一句,globalFilter往往都实现Orderer的,需要它个顺序,数值越小优先级越高,在后面filterHandlerMapping的时候,这些globalFilter会按顺序排好去执行的。

    public interface GlobalFilter {
    
        /**
         * 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);
    
    }
    

    GlobalFilter是一个接口,其实spring cloud gateway 里头已经有些定义好了的globalFilter,比如 NettyRoutingFilter、NettyWriteResponseFilter、ReactiveLoadBalancerClientFilter、NettyRoutingFilter & NettyWriteResponseFilter等等。


    内置的globalFilter(有过时的) globalFilter的处理顺序

    拿个ReactiveLoadBalancerClientFilter举例,ReactiveLoadBalancerClientFilter会根据 lb:// 前缀过滤处理,做负载均衡,选择最终要调用的服务地址,核心代码:

    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取请求url和前缀
        URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
        // 获取url scheme前缀
        String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
        // 1.如果请求url为空,或者不是lb开头,那直接跳过处理
        if (url == null
                || (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
            return chain.filter(exchange);
        }
        // 2.添加原始请求url到exchange里的GATEWAY_ORIGINAL_REQUEST_URL_ATTR(LinkedHashSet)
        addOriginalRequestUrl(exchange, url);
        return choose(exchange).doOnNext(response -> {
            // 3.获取负载均衡器,一般这里就是RibbonLoadBalancerClient
            ServiceInstance retrievedInstance = response.getServer();
            URI uri = exchange.getRequest().getURI();
            // 判断获取到的负载均衡器是用http还是https
            String overrideScheme = retrievedInstance.isSecure() ? "https" : "http";
        // 假设请求url的scheme前缀不为空,这里的逻辑应该是有问题的
            // 如果schemePrefix不是lb,那早在第一步就结束了
            if (schemePrefix != null) {
                // 那么委托的负载均衡器请求也使用同样的scheme:lb
                overrideScheme = url.getScheme();
            }
            // 构造一个委托的负载均衡器
            DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance(
                retrievedInstance, overrideScheme);
            // 由负载均衡器选出从多个提供服务的url里选出一个
            URI requestUrl = reconstructURI(serviceInstance, uri);
            // 然后把这个选出的url塞到ServerWebExchange里给其他过滤器用
            exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
        }).then(chain.filter(exchange));  
    }
    

    自定义globalFilter

    回归正题,我们可以自定义globalFilter,只需要实现globalFilter接口和ordered接口就行了。

    public class CustomGlobalFilter implements GlobalFilter, Ordered {
    
        public static final Integer CUSTOM_GLOBAL_FILTER_ORDER = 0;
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            System.out.println("let us see what is ServerWebExchange : " + exchange);
            //直接下一个
            //return chain.filter(exchange);
            long startTime = System.currentTimeMillis();
    
            return chain.filter(exchange).then().then(Mono.fromRunnable(() -> {
                //调用请求之后统计时间
                long endTime = System.currentTimeMillis();
                System.out.println(exchange.getRequest().getURI().getRawPath() + ", cost time : " + (endTime - startTime) + "ms");
            }));
        }
    
        @Override
        public int getOrder() {
            return CUSTOM_GLOBAL_FILTER_ORDER;
        }
    

    自定义局部filter

    自定义局部filter,只需要实现gatewayFilter,同时往往也实现ordered,最后是实现构造工厂,如SetResponseHeaderGatewayFilterFactory,仿造就可以了,注意命名格式,因为需要在配置文件用,FilterDefination的提取问题。

    public class CustomGatewayFilter implements GatewayFilter, Ordered {
    
        private AbstractNameValueGatewayFilterFactory.NameValueConfig config;
    
        public CustomGatewayFilter(AbstractNameValueGatewayFilterFactory.NameValueConfig config) {
            this.config = config;
        }
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            System.out.println("<-------------- BEGIN in custom gateway filter -------------->");
            System.out.println("do something before");
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                System.out.println("do something after");
                System.out.println("custom gateway filter : " + toString());
                System.out.println("<-------------- END in custom gateway filter -------------->");
            }));
        }
    
        @Override
        public int getOrder() {
            return 123;
        }
    
        @Override
        public String toString() {
            return filterToStringCreator(this)
                    .append(config.getName(), config.getValue()).toString();
        }
    }
    
    @Component //千万注意名字格式,XXX+GatewayFilterFactory
    public class CustomGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory{
    
        @Override
        public GatewayFilter apply(NameValueConfig config) {
            return new CustomGatewayFilter(config);
        }
    }
    

    最后在配置文件配置,filters那里,截取部分如下:

    routes: #配置路由
            - id: consumer_low
              uri: http://192.168.1.106:8000
              predicates:
                - Path=/cs/** #路径
                - Weight=group1,2 #权重
                - After=2021-01-20T17:42:47.789+08:00[Asia/Shanghai] #在这时间后生效
                - Before=2022-01-20T17:42:47.789+08:00[Asia/Shanghai] #在这时间前生效
                - Between=2021-01-20T17:42:47.789+08:00[Asia/Shanghai],2022-01-20T17:42:47.789+08:00[Asia/Shanghai] #在这时间区间生效
                - Method=GET #请求方式
                - Cookie=orion, li.ly1 #cookies,key-value格式,只有key是包含这个参数,如果还有value就是key的值要满足value正则,http://192.168.1.106:9001/cs/gatewayPredicate/testCookie,带上cookie,注意domain,path=/,过期时间
                - Query=marit, lar.sen # 请求参数,key-value格式,只有key是包含这个参数,如果还有value就是key的值要满足value正则,http://192.168.1.106:9001/cs/gatewayPredicate/testParam?orion=likly
                - Header=mitch, lu.cker #请求头,key-value格式,只有key是包含这个参数,如果还有value就是key的值要满足value正则,http://192.168.1.106:9001/cs/gatewayPredicate/testHeader,Header加mitch=lugcker
              filters: # 网关过滤器
                - StripPrefix=1
                - Custom=wawa,lala
    

    debug查看过滤器链:


    debug

    再看打印日志,可见其实是按filter chain来执行的:

    <-------------- BEGIN in custom global filter -------------->
    let us see what is ServerWebExchange : org.springframework.web.server.adapter.DefaultServerWebExchange@4c2e5532
    <-------------- BEGIN in custom gateway filter -------------->
    do something before
    do something after
    custom gateway filter : [CustomGatewayFilter wawa = 'lala']
    <-------------- END in custom gateway filter -------------->
    /cs/gatewayPredicate/testAll, cost time : 3850ms
    <-------------- END in custom global filter -------------->
    

    相关文章

      网友评论

          本文标题:spring cloud gateway中內置predicate

          本文链接:https://www.haomeiwen.com/subject/kgyvaltx.html