在“网关模块”一共定义了5个过滤器。分类如下:
继承AbstractGatewayFilterFactory的
实现GlobalFilter, Ordered接口
有以下几个问题需要解决
GlobalFilter 参考:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-combined-global-filter-and-gatewayfilter-ordering
GatewayFilterFactory参考:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories
关键是:GlobalFilter 针对“所有路由”,而 GatewayFilterFactory 针对“特定路由”
为了控制过滤器的顺序,Spring 的 Ordered 接口是根据 order 值升序排序的。
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
List<GatewayFilter> gatewayFilters = route.getFilters();
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
combined.addAll(gatewayFilters);
// TODO: needed or cached?
AnnotationAwareOrderComparator.sort(combined);
if (logger.isDebugEnabled()) {
logger.debug("Sorted gatewayFilterFactories: " + combined);
}
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
从以上 combine 可以看到先从请求 request 属性中获取了特定路由的过滤器gatewayFilters,在结合全局过滤器combined,最后经过 Ordered 排序。但是继承GatewayFilterFactory并没有指定 order 的值,只有实现 Ordered 接口才指定了 order 值,此时怎么处理GatewayFilterFactory的???
猜测:是不是跟 nacos 的网关 route 配置的 filters 的顺序有关呢。
结论:猜测正确✅
在 nacos 的网关配置文件 ruoyi-gateway-dev.yml 中给 ruoyi-auth 模块多配置了几个过滤器 filter。
spring:
redis:
host: localhost
port: 6379
password:
cloud:
gateway:
discovery:
locator:
lowerCaseServiceId: true
enabled: true
routes:
# 认证中心
- id: ruoyi-auth
uri: lb://ruoyi-auth
predicates:
- Path=/auth/**
filters:
# 验证码处理
- CacheRequestFilter
- ValidateCodeFilter
- StripPrefix=1
# 代码生成
- id: ruoyi-gen
uri: lb://ruoyi-gen
predicates:
- Path=/code/**
filters:
- StripPrefix=1
# 定时任务
- id: ruoyi-job
uri: lb://ruoyi-job
predicates:
- Path=/schedule/**
filters:
- StripPrefix=1
# 系统模块
- id: ruoyi-system
uri: lb://ruoyi-system
predicates:
- Path=/system/**
filters:
- StripPrefix=1
# 文件服务
- id: ruoyi-file
uri: lb://ruoyi-file
predicates:
- Path=/file/**
filters:
- StripPrefix=1
# 安全配置
security:
# 验证码
captcha:
enabled: true
type: math
# 防止XSS攻击
xss:
enabled: true
excludeUrls:
- /system/notice
# 不校验白名单
ignore:
whites:
- /auth/logout
- /auth/login
- /auth/register
- /*/v2/api-docs
- /csrf
其中给Auth模块特别配置了CacheRequestFilter、ValidateCodeFilter。其它模块全局使用了XssFilter、AuthFilter过滤器
全局的过滤器globalFilters是可以定义order值的,不能定义orderd值的局部过滤器(跟特定路由绑定)是依据 yml 配置文件配置的顺序(先配置的orderd值是1,递增的)。所以 yml 配置中只配置跟路由相关的局部过滤器。
结合gatewayFilters是按照配置文件的顺序(order是1,2,3依次递增),globalFilters也是按照order的顺序排序。所以对于RuoYi的过滤器来说顺序是:
AuthFilter(order=-200)
XssFilter(order=-100)
CacheRequestFilter(order=1)
ValidateCodeFilter(order=2)
StripPrefix(order=3)
语雀笔记地址:https://www.yuque.com/yuchangyuan/tkb5br
1、先找到断言处理器的映射规则类RoutePredicateHandlerMapping
2、该类的getHandlerInternal方法中的lookupRoute方法会决定采用哪一个route,并设置到request属性中
3、然后是FilteringWebHandler的handler方法
4、handler方法中获取到route的gatewayFilters和全局的globalFilters,然后按照order升序排序。
猜测route的gatewayFilters的order属性1,2,3是不是按照配置中心配置排序的。改变下配置中心的配置重新debug观察下。(猜测正确)