欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring Cloud Gateway 默認(rèn)的filter功能和執(zhí)行順序介紹

 更新時(shí)間:2021年10月14日 11:15:36   作者:giafei  
這篇文章主要介紹了Spring Cloud Gateway 默認(rèn)的filter功能和執(zhí)行順序,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Spring Cloud Gateway 默認(rèn)的filter功能和執(zhí)行順序

有效性

Spring Cloud Gateway 2.0.0.RELEASE

調(diào)試方法

新建一個(gè)GlobalFilter,在filter中加斷點(diǎn)即可調(diào)試filter,通過chain參數(shù)可以查看其它的filter及執(zhí)行順序(order)

filters(按執(zhí)行順序)

1. AdaptCachedBodyGlobalFilter

核心代碼

public int getOrder() {
    return Ordered.HIGHEST_PRECEDENCE + 1000;
}
public static final String CACHED_REQUEST_BODY_KEY = "cachedRequestBody";
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    Flux<DataBuffer> body = exchange.getAttributeOrDefault(CACHED_REQUEST_BODY_KEY, null);
    if (body != null) {
        ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
            @Override
            public Flux<DataBuffer> getBody() {
                return body;
            }
        };
        return chain.filter(exchange.mutate().request(decorator).build());
    }
    return chain.filter(exchange);
}

提供替換request 的 body的能力

2.NettyWriteResponseFilter

核心代碼

public static final int WRITE_RESPONSE_FILTER_ORDER = -1;
public int getOrder() {
    return WRITE_RESPONSE_FILTER_ORDER;
}
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    return chain.filter(exchange).then(Mono.defer(() -> {
        //見 后文的 NettyRoutingFilter
        HttpClientResponse clientResponse = exchange.getAttribute(CLIENT_RESPONSE_ATTR);
        ServerHttpResponse response = exchange.getResponse();
        NettyDataBufferFactory factory = (NettyDataBufferFactory) response.bufferFactory();
        
        final Flux<NettyDataBuffer> body = clientResponse.receive()
                .map(factory::wrap);
        MediaType contentType = response.getHeaders().getContentType();
        return (isStreamingMediaType(contentType) ?
                response.writeAndFlushWith(body.map(Flux::just)) : response.writeWith(body));
    }));
}

具體的將被代理的服務(wù)的內(nèi)容返回的類,文檔

3.ForwardPathFilter

核心代碼

public int getOrder() {
    return 0;
}
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
    URI routeUri = route.getUri();
    String scheme = routeUri.getScheme();
    if (isAlreadyRouted(exchange) || !"forward".equals(scheme)) {
        return chain.filter(exchange);
    }
    exchange = exchange.mutate().request(
            exchange.getRequest().mutate().path(routeUri.getPath()).build())
            .build();
    return chain.filter(exchange);
}

forward協(xié)議的url替換類

4.在Route中配置的各種GatewayFilter

核心代碼

/**
 * RouteDefinitionRouteLocator#loadGatewayFilters GatewayFilter的order
 */
ArrayList<GatewayFilter> ordered = new ArrayList<>(filters.size());
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;

根據(jù)配置不同實(shí)現(xiàn)具體的功能,詳見文檔

5.RouteToRequestUrlFilter

核心代碼

public static final int ROUTE_TO_URL_FILTER_ORDER = 10000;
public int getOrder() {
    return ROUTE_TO_URL_FILTER_ORDER;
}
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
    if (route == null) {
        return chain.filter(exchange);
    }
    URI uri = exchange.getRequest().getURI();
    boolean encoded = containsEncodedParts(uri);
    URI routeUri = route.getUri();
    
    //匹配 http:http://locahost:80/a/b/c?q=1,并把第一個(gè) http: 去掉
    if (hasAnotherScheme(routeUri)) {
        // uri格式 [scheme:]scheme-specific-part[#fragment]
        exchange.getAttributes().put(GATEWAY_SCHEME_PREFIX_ATTR, routeUri.getScheme());
        routeUri = URI.create(routeUri.getSchemeSpecificPart());
    }
    URI requestUrl = UriComponentsBuilder.fromUri(uri)
            .uri(routeUri)
            .build(encoded)
            .toUri();
    exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
    return chain.filter(exchange);
}
private static final String SCHEME_REGEX = "[a-zA-Z]([a-zA-Z]|\\d|\\+|\\.|-)*:.*";
static final Pattern schemePattern = Pattern.compile(SCHEME_REGEX);
static boolean hasAnotherScheme(URI uri) {
    return schemePattern.matcher(uri.getSchemeSpecificPart()).matches() && uri.getHost() == null
            && uri.getRawPath() == null;
}

路由功能的具體執(zhí)行類,文檔

6.LoadBalancerClientFilter(如果啟用了eureka)

核心代碼

public static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10100;
public int getOrder() {
    return LOAD_BALANCER_CLIENT_FILTER_ORDER;
}
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
    String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
    if (url == null || (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
        return chain.filter(exchange);
    }
    //一大波轉(zhuǎn)換操作
    addOriginalRequestUrl(exchange, url);
    final ServiceInstance instance = loadBalancer.choose(url.getHost());
    if (instance == null) {
        throw new NotFoundException("Unable to find instance for " + url.getHost());
    }
    URI uri = exchange.getRequest().getURI();
    String overrideScheme = null;
    if (schemePrefix != null) {
        overrideScheme = url.getScheme();
    }
    URI requestUrl = loadBalancer.reconstructURI(new DelegatingServiceInstance(instance, overrideScheme), uri);
    
    //轉(zhuǎn)換后的url填入 GATEWAY_REQUEST_URL_ATTR 屬性
    exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
    return chain.filter(exchange);
}

lb協(xié)議的路由功能,文檔

7.WebsocketRoutingFilter

核心代碼

public int getOrder() {
    return Ordered.LOWEST_PRECEDENCE - 1;
}
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    //upgrade頭 見https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism
    //或見 https://httpwg.org/specs/rfc7230.html#header.upgrade
    changeSchemeIfIsWebSocketUpgrade(exchange);
    //跳過一大波參數(shù)檢查與參數(shù)獲取
    return this.webSocketService.handleRequest(exchange,
            new ProxyWebSocketHandler(requestUrl, this.webSocketClient,
                    filtered, protocols));
}
/**
 * ProxyWebSocketHandler#handle 橋接兩個(gè)webSocket
 */
public Mono<Void> handle(WebSocketSession session) { //session為客戶端
    return client.execute(url, this.headers, new WebSocketHandler() {
        @Override
        public Mono<Void> handle(WebSocketSession proxySession) {   //proxySession為被代理的WebSocket
            Mono<Void> proxySessionSend = proxySession
                    .send(session.receive().doOnNext(WebSocketMessage::retain));
            Mono<Void> serverSessionSend = session
                    .send(proxySession.receive().doOnNext(WebSocketMessage::retain));
            return Mono.zip(proxySessionSend, serverSessionSend).then();
        }
        
        //省略其它方法
    });
} 

WebSocket的代理功能,文檔

8.NettyRoutingFilter

核心代碼

public int getOrder() {
    return Ordered.LOWEST_PRECEDENCE;
}
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
        //省略一大波參數(shù)獲取和參數(shù)校驗(yàn)
        final HttpMethod method = HttpMethod.valueOf(request.getMethod().toString());
        final String url = requestUrl.toString();
        return this.httpClient.request(method, url, req -> {
            //省略http數(shù)據(jù)發(fā)送代碼
        }).doOnNext(res -> {
            ServerHttpResponse response = exchange.getResponse();
            
            HttpHeaders headers = new HttpHeaders();
            res.responseHeaders().forEach(entry -> headers.add(entry.getKey(), entry.getValue()));
            //注意,如果ContentType為null會 NPE,特別是301或302跳轉(zhuǎn)
            exchange.getAttributes().put("original_response_content_type", headers.getContentType());
            //省略其它http解析代碼
            exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res);    //與前面的 NettyWriteResponseFilter 對應(yīng)
        }).then(chain.filter(exchange));
    }
} 

http協(xié)議的代理功能,文檔

9.ForwardRoutingFilter

核心代碼

public int getOrder() {
    return Ordered.LOWEST_PRECEDENCE;
}
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
    String scheme = requestUrl.getScheme();
    if (isAlreadyRouted(exchange) || !"forward".equals(scheme)) {
        return chain.filter(exchange);
    }
    setAlreadyRouted(exchange);
    if (log.isTraceEnabled()) {
        log.trace("Forwarding to URI: "+requestUrl);
    }
    return this.dispatcherHandler.handle(exchange);
}

將未處理的forward協(xié)議的請求交由spring來處理,文檔

其中 NettyRoutingFilter 和 NettyWriteResponseFilter 內(nèi)置有 WebClientHttpRoutingFilter和WebClientWriteResponseFilter 作為備用替換版本。

spring cloud gateway之filter實(shí)戰(zhàn)

1、filter的作用和生命周期

由filter工作流程點(diǎn),可以知道filter有著非常重要的作用,在“pre”類型的過濾器可以做參數(shù)校驗(yàn)、權(quán)限校驗(yàn)、流量監(jiān)控、日志輸出、協(xié)議轉(zhuǎn)換等,在“post”類型的過濾器中可以做響應(yīng)內(nèi)容、響應(yīng)頭的修改,日志的輸出,流量監(jiān)控等。首先需要弄清一點(diǎn)為什么需要網(wǎng)關(guān)這一層,這就不得不說下filter的作用了。

作用

當(dāng)我們有很多個(gè)服務(wù)時(shí),比如下圖中的user-service、goods-service、sales-service等服務(wù),客戶端請求各個(gè)服務(wù)的Api時(shí),每個(gè)服務(wù)都需要做相同的事情,比如鑒權(quán)、限流、日志輸出等。

在這里插入圖片描述

對于這樣重復(fù)的工作,有沒有辦法做的更好,答案是肯定的。在微服務(wù)的上一層加一個(gè)全局的權(quán)限控制、限流、日志輸出的Api Gatewat服務(wù),然后再將請求轉(zhuǎn)發(fā)到具體的業(yè)務(wù)服務(wù)層。這個(gè)Api Gateway服務(wù)就是起到一個(gè)服務(wù)邊界的作用,外接的請求訪問系統(tǒng),必須先通過網(wǎng)關(guān)層。

生命周期

Spring Cloud Gateway同zuul類似,有“pre”和“post”兩種方式的filter??蛻舳说恼埱笙冉?jīng)過“pre”類型的filter,然后將請求轉(zhuǎn)發(fā)到具體的業(yè)務(wù)服務(wù),比如上圖中的user-service,收到業(yè)務(wù)服務(wù)的響應(yīng)之后,再經(jīng)過“post”類型的filter處理,最后返回響應(yīng)到客戶端。

在這里插入圖片描述

與zuul不同的是,filter除了分為“pre”和“post”兩種方式的filter外,在Spring Cloud Gateway中,filter從作用范圍可分為另外兩種,一種是針對于單個(gè)路由的gateway filter,它在配置文件中的寫法同predict類似;另外一種是針對于所有路由的global gateway filer?,F(xiàn)在從作用范圍劃分的維度來講解這兩種filter。

gateway filter

過濾器允許以某種方式修改傳入的HTTP請求或傳出的HTTP響應(yīng)。過濾器可以限定作用在某些特定請求路徑上。 Spring Cloud Gateway包含許多內(nèi)置的GatewayFilter工廠。

GatewayFilter工廠同上一篇介紹的Predicate工廠類似,都是在配置文件application.yml中配置,遵循了約定大于配置的思想,只需要在配置文件配置GatewayFilter Factory的名稱,而不需要寫全部的類名,比如AddRequestHeaderGatewayFilterFactory只需要在配置文件中寫AddRequestHeader,而不是全部類名。在配置文件中配置的GatewayFilter Factory最終都會相應(yīng)的過濾器工廠類處理。

Spring Cloud Gateway 內(nèi)置的過濾器工廠一覽表如下:

現(xiàn)在挑幾個(gè)常見的過濾器工廠來講解,每一個(gè)過濾器工廠在官方文檔都給出了詳細(xì)的使用案例,如果不清楚的還可以在org.springframework.cloud.gateway.filter.factory看每一個(gè)過濾器工廠的源碼。

2、AddRequestHeader GatewayFilter Factory

A.創(chuàng)建子工程gateway-filter

B.引入相關(guān)的依賴

<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-gateway</artifactId>
		</dependency>
	</dependencies>

C.application.yml

server:
  port: 8081
spring:
  profiles:
    active: add_request_header_route
---
spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: http://httpbin.org:80/get
        filters:
        - AddRequestHeader=X-Request-Foo, Bar
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
  profiles: add_request_header_route

在上述的配置中,工程的啟動端口為8081,配置文件為add_request_header_route,在add_request_header_route配置中,配置了roter的id為add_request_header_route,路由地址為http://httpbin.org:80/get,該router有AfterPredictFactory,有一個(gè)filter為AddRequestHeaderGatewayFilterFactory(約定寫成AddRequestHeader),AddRequestHeader過濾器工廠會在請求頭加上一對請求頭,名稱為X-Request-Foo,值為Bar。為了驗(yàn)證AddRequestHeaderGatewayFilterFactory是怎么樣工作的,查看它的源碼,AddRequestHeaderGatewayFilterFactory的源碼如下:

public class AddRequestHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
	@Override
	public GatewayFilter apply(NameValueConfig config) {
		return (exchange, chain) -> {
			ServerHttpRequest request = exchange.getRequest().mutate()
					.header(config.getName(), config.getValue())
					.build();
			return chain.filter(exchange.mutate().request(request).build());
		};
    }
}

由上面的代碼可知,根據(jù)舊的ServerHttpRequest創(chuàng)建新的 ServerHttpRequest ,在新的ServerHttpRequest加了一個(gè)請求頭,然后創(chuàng)建新的 ServerWebExchange ,提交過濾器鏈繼續(xù)過濾。

啟動工程,通過curl命令來模擬請求:

curl localhost:8081

最終顯示了從 http://httpbin.org:80/get得到了請求,響應(yīng)如下:

{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Connection": "close",
    "Forwarded": "proto=http;host=\"localhost:8081\";for=\"0:0:0:0:0:0:0:1:56248\"",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.58.0",
    "X-Forwarded-Host": "localhost:8081",
    "X-Request-Foo": "Bar"
  },
  "origin": "0:0:0:0:0:0:0:1, 210.22.21.66",
  "url": "http://localhost:8081/get"
}

可以上面的響應(yīng)可知,確實(shí)在請求頭中加入了X-Request-Foo這樣的一個(gè)請求頭,在配置文件中配置的AddRequestHeader過濾器工廠生效。

跟AddRequestHeader過濾器工廠類似的還有AddResponseHeader過濾器工廠,在此就不再重復(fù)。

RewritePath GatewayFilter Factory

在Nginx服務(wù)啟中有一個(gè)非常強(qiáng)大的功能就是重寫路徑,Spring Cloud Gateway默認(rèn)也提供了這樣的功能,這個(gè)功能是Zuul沒有的。在配置文件中加上以下的配置:

spring:
  profiles:
    active: rewritepath_route
---
spring:
  cloud:
    gateway:
      routes:
      - id: rewritepath_route
        uri: https://blog.csdn.net
        predicates:
        - Path=/foo/**
        filters:
        - RewritePath=/foo/(?<segment>.*), /$\{segment}
  profiles: rewritepath_route

上面的配置中,所有的/foo/**開始的路徑都會命中配置的router,并執(zhí)行過濾器的邏輯,在本案例中配置了RewritePath過濾器工廠,此工廠將/foo/(?.*)重寫為{segment},然后轉(zhuǎn)發(fā)到https://blog.csdn.net。比如在網(wǎng)頁上請求localhost:8081/foo/forezp,此時(shí)會將請求轉(zhuǎn)發(fā)到https://blog.csdn.net/forezp的頁面,比如在網(wǎng)頁上請求localhost:8081/foo/forezp/1,頁面顯示404,就是因?yàn)椴淮嬖趆ttps://blog.csdn.net/forezp/1這個(gè)頁面。

自定義過濾器

Spring Cloud Gateway內(nèi)置了19種強(qiáng)大的過濾器工廠,能夠滿足很多場景的需求,那么能不能自定義自己的過濾器呢,當(dāng)然是可以的。在spring Cloud Gateway中,過濾器需要實(shí)現(xiàn)GatewayFilter和Ordered2個(gè)接口。寫一個(gè)RequestTimeFilter,代碼如下:

public class RequestTimeFilter implements GatewayFilter, Ordered {
    private static final Log log = LogFactory.getLog(GatewayFilter.class);
    private static final String REQUEST_TIME_BEGIN = "requestTimeBegin";
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        exchange.getAttributes().put(REQUEST_TIME_BEGIN, System.currentTimeMillis());
        return chain.filter(exchange).then(
                Mono.fromRunnable(() -> {
                    Long startTime = exchange.getAttribute(REQUEST_TIME_BEGIN);
                    if (startTime != null) {
                        log.info(exchange.getRequest().getURI().getRawPath() + ": " + (System.currentTimeMillis() - startTime) + "ms");
                    }
                })
        );
    }
    @Override
    public int getOrder() {
        return 0;
    }
}

在上面的代碼中,Ordered中的int getOrder()方法是來給過濾器設(shè)定優(yōu)先級別的,值越大則優(yōu)先級越低。還有有一個(gè)filterI(exchange,chain)方法,在該方法中,先記錄了請求的開始時(shí)間,并保存在ServerWebExchange中,此處是一個(gè)“pre”類型的過濾器,然后再chain.filter的內(nèi)部類中的run()方法中相當(dāng)于"post"過濾器,在此處打印了請求所消耗的時(shí)間。然后將該過濾器注冊到router中,代碼如下:

@Bean
    public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
        // @formatter:off
        return builder.routes()
                .route(r -> r.path("/customer/**")
                        .filters(f -> f.filter(new RequestTimeFilter())
                                .addResponseHeader("X-Response-Default-Foo", "Default-Bar"))
                        .uri("http://httpbin.org:80/get")
                        .order(0)
                        .id("customer_filter_router")
                )
                .build();
        // @formatter:on
    }

自定義過濾器工廠

在上面的自定義過濾器中,有沒有辦法自定義過濾器工廠類呢?這樣就可以在配置文件中配置過濾器了?,F(xiàn)在需要實(shí)現(xiàn)一個(gè)過濾器工廠,在打印時(shí)間的時(shí)候,可以設(shè)置參數(shù)來決定是否打印請參數(shù)。查看GatewayFilterFactory的源碼,可以發(fā)現(xiàn)GatewayFilterfactory的層級如下:

在這里插入圖片描述

過濾器工廠的頂級接口是GatewayFilterFactory,我們可以直接繼承它的兩個(gè)抽象類來簡化開發(fā)AbstractGatewayFilterFactory和AbstractNameValueGatewayFilterFactory,這兩個(gè)抽象類的區(qū)別就是前者接收一個(gè)參數(shù)(像StripPrefix和我們創(chuàng)建的這種),后者接收兩個(gè)參數(shù)(像AddResponseHeader)。

過濾器工廠的頂級接口是GatewayFilterFactory,有2個(gè)兩個(gè)較接近具體實(shí)現(xiàn)的抽象類,分別為AbstractGatewayFilterFactory和AbstractNameValueGatewayFilterFactory,這2個(gè)類前者接收一個(gè)參數(shù),比如它的實(shí)現(xiàn)類RedirectToGatewayFilterFactory;后者接收2個(gè)參數(shù),比如它的實(shí)現(xiàn)類AddRequestHeaderGatewayFilterFactory類?,F(xiàn)在需要將請求的日志打印出來,需要使用一個(gè)參數(shù),這時(shí)可以參照RedirectToGatewayFilterFactory的寫法。

public class RequestTimeGatewayFilterFactory extends AbstractGatewayFilterFactory<RequestTimeGatewayFilterFactory.Config> {
    private static final Log log = LogFactory.getLog(GatewayFilter.class);
    private static final String REQUEST_TIME_BEGIN = "requestTimeBegin";
    private static final String KEY = "withParams";
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList(KEY);
    }
    public RequestTimeGatewayFilterFactory() {
        super(Config.class);
    }
    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            exchange.getAttributes().put(REQUEST_TIME_BEGIN, System.currentTimeMillis());
            return chain.filter(exchange).then(
                    Mono.fromRunnable(() -> {
                        Long startTime = exchange.getAttribute(REQUEST_TIME_BEGIN);
                        if (startTime != null) {
                            StringBuilder sb = new StringBuilder(exchange.getRequest().getURI().getRawPath())
                                    .append(": ")
                                    .append(System.currentTimeMillis() - startTime)
                                    .append("ms");
                            if (config.isWithParams()) {
                                sb.append(" params:").append(exchange.getRequest().getQueryParams());
                            }
                            log.info(sb.toString());
                        }
                    })
            );
        };
    }
    public static class Config {
        private boolean withParams;
        public boolean isWithParams() {
            return withParams;
        }
        public void setWithParams(boolean withParams) {
            this.withParams = withParams;
        }
    }
}

在上面的代碼中 apply(Config config)方法內(nèi)創(chuàng)建了一個(gè)GatewayFilter的匿名類,具體的實(shí)現(xiàn)邏輯跟之前一樣,只不過加了是否打印請求參數(shù)的邏輯,而這個(gè)邏輯的開關(guān)是config.isWithParams()。靜態(tài)內(nèi)部類類Config就是為了接收那個(gè)boolean類型的參數(shù)服務(wù)的,里邊的變量名可以隨意寫,但是要重寫List shortcutFieldOrder()這個(gè)方法。。

需要注意的是,在類的構(gòu)造器中一定要調(diào)用下父類的構(gòu)造器把Config類型傳過去,否則會報(bào)ClassCastException

最后,需要在工程的啟動文件Application類中,向Srping Ioc容器注冊RequestTimeGatewayFilterFactory類的Bean。

@Bean
    public RequestTimeGatewayFilterFactory elapsedGatewayFilterFactory() {
        return new RequestTimeGatewayFilterFactory();
    }

然后可以在配置文件中配置如下:

spring:
  profiles:
    active: elapse_route
---
spring:
  cloud:
    gateway:
      routes:
      - id: elapse_route
        uri: http://httpbin.org:80/get
        filters:
        - RequestTime=false
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
  profiles: elapse_route

啟動工程,在瀏覽器上訪問localhost:8081?name=forezp,可以在控制臺上看到,日志輸出了請求消耗的時(shí)間和請求參數(shù)。

global filter

Spring Cloud Gateway根據(jù)作用范圍劃分為GatewayFilter和GlobalFilter,二者區(qū)別如下:

  • GatewayFilter : 需要通過spring.cloud.routes.filters 配置在具體路由下,只作用在當(dāng)前路由上或通過spring.cloud.default-filters配置在全局,作用在所有路由上
  • GlobalFilter : 全局過濾器,不需要在配置文件中配置,作用在所有的路由上,最終通過GatewayFilterAdapter包裝成GatewayFilterChain可識別的過濾器,它為請求業(yè)務(wù)以及路由的URI轉(zhuǎn)換為真實(shí)業(yè)務(wù)服務(wù)的請求地址的核心過濾器,不需要配置,系統(tǒng)初始化時(shí)加載,并作用在每個(gè)路由上。

Spring Cloud Gateway框架內(nèi)置的GlobalFilter如下:

在這里插入圖片描述

上圖中每一個(gè)GlobalFilter都作用在每一個(gè)router上,能夠滿足大多數(shù)的需求。但是如果遇到業(yè)務(wù)上的定制,可能需要編寫滿足自己需求的GlobalFilter。在下面的案例中將講述如何編寫自己GlobalFilter,該GlobalFilter會校驗(yàn)請求中是否包含了請求參數(shù)“token”,如何不包含請求參數(shù)“token”則不轉(zhuǎn)發(fā)路由,否則執(zhí)行正常的邏輯。代碼如下:

public class TokenFilter implements GlobalFilter, Ordered {
    Logger logger=LoggerFactory.getLogger( TokenFilter.class );
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (token == null || token.isEmpty()) {
            logger.info( "token is empty..." );
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }
    @Override
    public int getOrder() {
        return -100;
    }
}

在上面的TokenFilter需要實(shí)現(xiàn)GlobalFilter和Ordered接口,這和實(shí)現(xiàn)GatewayFilter很類似。然后根據(jù)ServerWebExchange獲取ServerHttpRequest,然后根據(jù)ServerHttpRequest中是否含有參數(shù)token,如果沒有則完成請求,終止轉(zhuǎn)發(fā),否則執(zhí)行正常的邏輯。

然后需要將TokenFilter在工程的啟動類中注入到Spring Ioc容器中,代碼如下:

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

啟動工程,使用curl命令請求:

curl localhost:8081/customer/123

可以看到請沒有被轉(zhuǎn)發(fā),請求被終止,并在控制臺打印了如下日志:

2018-11-16 15:30:13.543 INFO 19372 — [ctor-http-nio-2] gateway.TokenFilter

上面的日志顯示了請求進(jìn)入了沒有傳“token”的邏輯。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java實(shí)現(xiàn)inputstream流的復(fù)制代碼實(shí)例

    Java實(shí)現(xiàn)inputstream流的復(fù)制代碼實(shí)例

    這篇文章主要介紹了Java實(shí)現(xiàn)inputstream流的復(fù)制代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Java中CyclicBarrier的理解與應(yīng)用詳解

    Java中CyclicBarrier的理解與應(yīng)用詳解

    這篇文章主要介紹了Java中CyclicBarrier的理解與應(yīng)用詳解,CyclicBarrier類是JUC框架中的工具類,也是一個(gè)同步輔助裝置:允許多個(gè)線程去等待直到全部線程抵達(dá)了公共的柵欄點(diǎn),需要的朋友可以參考下
    2023-12-12
  • 詳解Spring Boot 定制HTTP消息轉(zhuǎn)換器

    詳解Spring Boot 定制HTTP消息轉(zhuǎn)換器

    本篇文章主要介紹了詳解Spring Boot 定制HTTP消息轉(zhuǎn)換器,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-11-11
  • MybatisPlus實(shí)現(xiàn)邏輯刪除功能

    MybatisPlus實(shí)現(xiàn)邏輯刪除功能

    這篇文章主要介紹了MybatisPlus實(shí)現(xiàn)邏輯刪除功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Spring boot validation校驗(yàn)方法實(shí)例

    Spring boot validation校驗(yàn)方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于Spring boot validation校驗(yàn)方法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • SiteMesh如何結(jié)合Freemarker及velocity使用

    SiteMesh如何結(jié)合Freemarker及velocity使用

    這篇文章主要介紹了SiteMesh如何結(jié)合Freemarker及velocity使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Spring boot 集成 Druid 數(shù)據(jù)源過程詳解

    Spring boot 集成 Druid 數(shù)據(jù)源過程詳解

    這篇文章主要介紹了Spring boot 集成 Druid 數(shù)據(jù)源過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • Java中Lock鎖基本使用方法詳解

    Java中Lock鎖基本使用方法詳解

    鎖是一種工具,用于控制對共享資源的訪問Lock和synchronized是最常見的兩個(gè)鎖,他們都能夠達(dá)到線程安全的目錄,這篇文章主要給大家介紹了關(guān)于Java中Lock鎖基本使用方法詳解的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • Java生成UUID的常用方式示例代碼

    Java生成UUID的常用方式示例代碼

    UUID保證對在同一時(shí)空中的所有機(jī)器都是唯一的,通常平臺會提供生成的API,按照開放軟件基金會(OSF)制定的標(biāo)準(zhǔn)計(jì)算,用到了以太網(wǎng)卡地址、納秒級時(shí)間、芯片ID碼和許多可能的數(shù)字,下面這篇文章主要給大家介紹了關(guān)于Java生成UUID的常用方式,需要的朋友可以參考下
    2023-05-05
  • 教你怎么通過IDEA設(shè)置堆內(nèi)存空間

    教你怎么通過IDEA設(shè)置堆內(nèi)存空間

    這篇文章主要介紹了教你怎么通過IDEA設(shè)置堆內(nèi)存空間,文中有非常詳細(xì)的代碼示例,對正在使用IDEA的小伙伴們很有幫助喲,需要的朋友可以參考下
    2021-05-05

最新評論