spring cloud gateway 不生效
自定义过滤器需要实现和Ordered。其中中的这个方法就是用来实现你的自定义的逻辑的示例:统计某个服务的响应时间。
要说到gateway网关过滤,那一定要明白-过滤器-自定义局部、全局过滤器、区别。
前两天调试gateway网关问题,发现GatewayFilter和GlobalFilter使用错了,导致导致网关拦截失效,搞了一上午才找到问题。
自定义过滤器需要实现GatewayFilter
和Ordered
。其中GatewayFilter
中的这个方法就是用来实现你的自定义的逻辑的
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
示例:统计某个服务的响应时间
1.1、创建Filer
[](javascript:void(0); “复制代码”)
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;
}
}
[](javascript:void(0); “复制代码”)
在请求刚刚到达时,往ServerWebExchange
中放入了一个属性elapsedTimeBegin
,属性值为当时的毫秒级时间戳。然后在请求执行结束后,又从中取出我们之前放进去的那个时间戳,与当前时间的差值即为该请求的耗时。因为这是与业务无关的日志所以将Ordered
设为Integer.MAX_VALUE
以降低优先级。
chain.filter(exchange)
之前的就是 “pre” 部分,之后的也就是then
里边的是 “post” 部分。
1.2、配置
创建好 Filter 之后我们将它添加到我们的 Filter Chain 里边
[](javascript:void(0); “复制代码”)
@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
}
[](javascript:void(0); “复制代码”)
注意:实际在使用 Spring Cloud 的过程中,需要使用 Sleuth+Zipkin 来进行耗时分析。
二、全局过滤器
有多个路由就需要一个一个来配置,并不能通过像下面这样来实现全局有效(也未在 Fluent Java API 中找到能设置 defaultFilters 的方法)
@Bean public ElapsedFilter elapsedFilter(){ return new ElapsedFilter();
}
自定义过滤器需要实现GlobalFilter和Ordered
。
示例:校验token
2.1、创建Filter
[](javascript:void(0); “复制代码”)
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;
}
}
[](javascript:void(0); “复制代码”)
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 filter(ServerWebExchange exchange, GatewayFilterChain chain),唯一的区别就是GatewayFilter继承了ShortcutConfigurable,GlobalFilter没有任何继承。
参看示例一:Gateway Filter与RouteLocator绑定使用
3.2、GlobalFilter
Spring Cloud gateway定义了GlobalFilter的接口让我们去自定义实现自己的的GlobalFilter。GlobalFilter是一个全局的Filter,作用于所有的路由。
让其在Gateway中运行生效,有两种方式一种直接加[@Component](https://github.com/Component "@Component")
注解,另外一种可以在 Spring Config 中配置这个 Bean如下示例二所示;
更多推荐
所有评论(0)