Spring Cloud Gateway Global Filter vs Gateway filter
概述
Spring Cloud Gateway 中的 filter 分为 global filter 和 gateway filter,global filter 作用于所有的路由,gateway filter 一般作用于特定的路由,也可以配置默认 gateway filter,默认 gateway filter 作用于所有路由。不论是 global filter 还是 gateway filter,他们的作用都是类似的:对请求和响应做出某种修改。
注①:以下会交替使用“全局 filter” 和 global filter,他们表达相同的含义。
注②:filter 的逻辑分为两个部分,一个部分逻辑在请求处理之前(pre logic),另一部分处理逻辑在响应之后(post logic),所以如果 A filter 优先级高于 B filter,那么 A 的 pre logic 在 B 的 pre logic 之前执行,但是 B 的 post logic 在 A 的 post logic 之前执行。
注③:严格来说,pre logic 执行是在上一个 filter 的 pre logic 之后执行,post logic 在上一个 filter 的 post logic 之前或响应之后执行。
注④:pre logic 和 post logic 更多说明参考最后一节。
Global Filter
Global Filter 的接口定义如下:
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);
}
全局 filter 一个典型的用法是身份认证拦截器,只需要实现 GlobalFilter 接口即可,如果有多个全局 filter,且拦截器逻辑之间存在顺序关系,则需要实现 Ordered 接口。
@Component
public class AuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 这里实现身份认证逻辑,
}
// ...
}
Gateway Filter
作用于特定的路由,他的作用和 Global filter 相同,都是为了修改请求或者响应,比方说给请求加上某个请求头,或者给响应加上某个响应头等等。一个路由可以配置多个 filter,给路由配置 filter 很简单,例如我们想给 id 为 some_route 的路由配置一个 AddRequestHeader filter,只需要配置如下:
spring:
cloud:
gateway:
routes:
- id: some_route
uri: https://example.org
filters:
- AddRequestHeader=X-Request-red, blue
spring 内置了很多常用的 filter,大家可自行查看。上面的配置中 filters 是一个数组,目前只配置了 AddRequestHeader filter,filter 配置的语法是:<filter name>=<filter config params>
。
filter 的名字是 filter 对应的工厂类的名字去掉 “GatewayFilterFactory” 而得来,AddRequestHeader filter 对应的工厂类为 AddRequestHeaderGatewayFilterFactory,因此 filter 的名字为 AddRequestHeader。filter config params 则是传递给 filter 的配置参数,配置参数也是在 filter 工厂类中通过内部类的方式定义的。
举个例子,我们实现一个黑名单拦截的过滤器,可以自定义一个以 GatewayFilterFactory 作为结尾的类 BlackListIpGatewayFilterFactory(注:非必须,但是是推荐的命名方式),实现 GatewayFilterFactory 接口或者继承 AbstractGatewayFilterFactory 抽象类,同时定义一个内部类 Config,用于接收配置参数,代码如下:
@Component
public class BlackListIpGatewayFilterFactory extends AbstractGatewayFilterFactory<BlackListIpGatewayFilterFactory.Config> {
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
// 如果请求 ip 在 blacklistIps 中就拦截,这里省略实现部分
return chain.filter(exchange);
};
}
public BlackListIpFilter() {
super(Config.class);
}
public static class Config {
private List<String> blacklistIps;
public List<String> getBlacklistIps() {
return blacklistIps;
}
public void setBlacklistIps(List<String> blacklistIps) {
this.blacklistIps = blacklistIps;
}
}
}
从上面的代码可以看出,过滤器的逻辑实现被封装在 apply 方法返回的 GatewayFilter 对象中,实现了 filter 之后,我们就可以将 filter 配置到特定的路由上:
spring:
cloud:
gateway:
routes:
- id: some_route1
uri: https://example.org
filters:
- BlackListIp=192.168.2.124,192.168.2.158
默认 Gateway Filter
在概述部分提到了默认 gateway filter 也可应用于所有路由,那么“默认 gateway filter” 和全局 filter 有什么区别呢?在讨论这个问题之前,先看默认 Gateway filter 的配置方式:
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Red, Default-Blue
默认 gateway filter 和全局 filter 在于:每个路由都会有一个默认 gateway filter 实例,但是全局 filter 是所有路由共享的。
框架层面无区别
不论是全局 filter 还是 gateway filter,他们最终都是被包装成 OrderedGatewayFilter,然后排序这些 filter,让请求和响应依次经过排序后的 filter 处理。所以在框架层面他们都是 filter,目的都是为了处理请求和响应,并无本质的不同。所以官方给的架构图并没有区分 global filter 和 gateway filter:
一个路由的 filters 包括 global filters 和该路由本身配置的 gateway filters(route scoped),这一点可以在 FilteringWebHandler#handle 方法中看出:
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
// 路由本身的 filters
List<GatewayFilter> gatewayFilters = route.getFilters();
// 全局 filters
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
// 全局 filters + 路由本身的 filters
combined.addAll(gatewayFilters);
AnnotationAwareOrderComparator.sort(combined);
if (logger.isDebugEnabled()) {
logger.debug("Sorted gatewayFilterFactories: " + combined);
}
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
pre logic and post logic
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
// pre loigic 写在 chain.filter 之前
// chain.filter 会将请求转发给下一个 filter 处理
return chain.filter(exchange)
.then(Mono.fromRunnable(() -> {
// 写在这个地方的是 post logic
}));
};
}
温馨提示:反馈需要登录