0%

如何在Spring cloud gateway全局filter中获取本次请求命中的路由id

首先开启gateway debug日志,可以看到:

debug

debug日志中是可以打印请求所命中的路由id的,Route matched: hello-route

然后我在想怎么在程序中获取到这个id呢?因为如果在程序中可以获取到这个id,我就可以按统计每个路由所被访问的次数。网上找了一些博客,都没有提到这个问题,所以只能自己想了。

首先我从打印日志的类开始搜,打开源码RoutePredicateHandlerMapping,找到打印日志的代码。

protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
    if (this.managmentPort != null && exchange.getRequest().getURI().getPort() == this.managmentPort) {
        return Mono.empty();
    } else {
        exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_HANDLER_MAPPER_ATTR, this.getSimpleName());
        return this.lookupRoute(exchange).flatMap((r) -> {
            exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
            if (this.logger.isDebugEnabled()) {
                // 可以看到这里对应的r就是我们要获取的路由。因为从打印的日志中可以看出
                this.logger.debug("Mapping [" + this.getExchangeDesc(exchange) + "] to " + r);
            }

            exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR, r);
            return Mono.just(this.webHandler);
        }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
            exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No RouteDefinition found for [" + this.getExchangeDesc(exchange) + "]");
            }

        })));
    }
}
Route{id='hello-route', uri=http://127.0.0.1:8763, order=0, predicate=org.springframework........

我们只要获取到这个Route对象就可以了。那么源码中这个对象放哪儿了呢?

exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR, r);

所以我们只需要在exchange中根据ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR,这个keyAttributes获取就可以了。

下面编写一个Global Filter试试吧。

public class GatewayLogFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        Route route = (Route) exchange.getAttributes().get(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
        System.out.println(route.getId());
        return chain.filter(exchange);
    }

}