010-spring cloud gateway-過濾器-自定義局部、全局過濾器、區別


一、自定義局部過濾器

  自定義過濾器需要實現GatewayFilterOrdered。其中GatewayFilter中的這個方法就是用來實現你的自定義的邏輯的

Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);

示例:統計某個服務的響應時間

1.1、創建Filer

public class ElapsedFilter implements GatewayFilter, Ordered {

    private static final Log log = LogFactory.getLog(GatewayFilter.class);
    private static final String ELAPSED_TIME_BEGIN = "elapsedTimeBegin";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        exchange.getAttributes().put(ELAPSED_TIME_BEGIN, System.currentTimeMillis());
        return chain.filter(exchange).then(
                Mono.fromRunnable(() -> {
                    Long startTime = exchange.getAttribute(ELAPSED_TIME_BEGIN);
                    if (startTime != null) {
                        log.info(exchange.getRequest().getURI().getRawPath() + ": " + (System.currentTimeMillis() - startTime) + "ms");
                    }
                })
        );
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}

在請求剛剛到達時,往ServerWebExchange中放入了一個屬性elapsedTimeBegin,屬性值為當時的毫秒級時間戳。然后在請求執行結束后,又從中取出我們之前放進去的那個時間戳,與當前時間的差值即為該請求的耗時。因為這是與業務無關的日志所以將Ordered設為Integer.MAX_VALUE以降低優先級。

chain.filter(exchange)之前的就是 “pre” 部分,之后的也就是then里邊的是 “post” 部分。

1.2、配置

創建好 Filter 之后我們將它添加到我們的 Filter Chain 里邊

@Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
    // @formatter:off
    return builder.routes()
            .route(r -> r.path("/fluent/customer/**")
                         .filters(f -> f.stripPrefix(2)
                                        .filter(new ElapsedFilter())
                                        .addResponseHeader("X-Response-Default-Foo", "Default-Bar"))
                         .uri("lb://CONSUMER")
                         .order(0)
                         .id("fluent_customer_service")
            )
            .build();
    // @formatter:on
}

注意:實際在使用 Spring Cloud 的過程中,需要使用 Sleuth+Zipkin 來進行耗時分析。

二、全局過濾器

有多個路由就需要一個一個來配置,並不能通過像下面這樣來實現全局有效(也未在 Fluent Java API 中找到能設置 defaultFilters 的方法)

@Bean
public ElapsedFilter elapsedFilter(){
    return new ElapsedFilter();
}

自定義過濾器需要實現GlobalFilter和Ordered

示例:校驗token

2.1、創建Filter

public class TokenFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (token == null || token.isEmpty()) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -100;
    }
}

2.2、在 Spring Config 中配置這個 Bean

@Bean
public TokenFilter tokenFilter(){
    return new TokenFilter();
}

三、GatewayFilter與GlobalFilter的區別

3.1、GatewayFilter

  在一個高的角度來看,Global filters會被應用到所有的路由上,而Gateway filter將應用到單個路由上或者一個分組的路由上。

  GatewayFilter是從WebFilter中Copy過來的,相當於一個Filter過濾器,可以對訪問的URL過濾橫切處理,應用場景比如超時,安全等。

  GatewayFilter和GlobalFilter兩個接口中定義的方法一樣都是Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain),唯一的區別就是GatewayFilter繼承了ShortcutConfigurable,GlobalFilter沒有任何繼承。

  參看示例一:Gateway Filter與RouteLocator綁定使用

3.2、GlobalFilter

  Spring Cloud gateway定義了GlobalFilter的接口讓我們去自定義實現自己的的GlobalFilter。GlobalFilter是一個全局的Filter,作用於所有的路由。

  讓其在Gateway中運行生效,有兩種方式一種直接加@Component注解,另外一種可以在 Spring Config 中配置這個 Bean如下示例二所示;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM