Spring Reactive(Kotlin)中WebFilter未触发及上下文设置失效问题
问题分析与解决方案
一、WebFilter未触发的排查点
1. 确认WebFlux环境
Spring Boot 3中,若同时引入spring-boot-starter-web(Servlet栈)和spring-boot-starter-webflux(Reactive栈),默认会启用Servlet环境,此时WebFlux的WebFilter不会生效。需确保项目仅依赖WebFlux:
// build.gradle.kts 示例 dependencies { implementation("org.springframework.boot:spring-boot-starter-webflux") // 若之前误引入Web依赖,需排除 // implementation("org.springframework.boot:spring-boot-starter-web") { exclude(module = "spring-boot-starter-tomcat") } }
2. 确保Filter被正确扫描
- 检查
CustomWebFilter所在包是否在Spring Boot组件扫描范围内(默认扫描启动类所在包及子包),若不在,需在启动类上添加@ComponentScan(basePackages = ["com.your.package"])。 - 或直接通过
@Bean手动注册Filter,规避扫描问题:
@Configuration class WebFilterConfig { @Bean fun customWebFilter(): WebFilter { return CustomWebFilter() } }
3. 调整Filter执行优先级
若存在其他Filter拦截请求,可通过@Order注解设置更高优先级,确保当前Filter先执行:
@Component @Order(Ordered.HIGHEST_PRECEDENCE) class CustomWebFilter : WebFilter { // ... 原有代码 }
4. 验证路径匹配范围
WebFlux的WebFilter默认匹配所有路径,若需限定范围,可显式判断路径确保覆盖目标请求:
@Component class CustomWebFilter : WebFilter { override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> { // 仅处理/api前缀的请求(可选) if (!exchange.request.path.value().startsWith("/api/")) { return chain.filter(exchange) } // ... 原有逻辑 } }
二、上下文传递逻辑优化
即使Filter触发,若上下文写入逻辑有误也会导致读取失败,可简化写法确保正确性:
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> { val tenant = exchange.request.headers["tenant-header"]?.firstOrNull() ?: "default" // 直接使用Context.of简化上下文写入 return chain.filter(exchange).contextWrite(Context.of("tenant", tenant)) }
三、替代实现方案
若WebFilter方案仍无法解决问题,可尝试以下两种租户信息传递方式:
1. 存入ServerWebExchange Attributes
将租户信息存入请求交换对象的属性中,后续通过ServerWebExchange直接读取:
// Filter中存入 override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> { val tenant = exchange.request.headers["tenant-header"]?.firstOrNull() ?: "default" exchange.attributes["tenant"] = tenant return chain.filter(exchange) } // Controller中读取 @GetMapping("/test") fun test(exchange: ServerWebExchange): Mono<String> { val tenant = exchange.attributes["tenant"] as? String ?: "" return Mono.just(tenant) }
2. 结合@RequestHeader直接获取
若仅在Controller层需要租户信息,可直接通过@RequestHeader注解读取,无需经过Filter:
@GetMapping("/test") fun test(@RequestHeader(value = "tenant-header", defaultValue = "default") tenant: String): Mono<String> { return Mono.just(tenant) }
内容的提问来源于stack exchange,提问作者Nabeel Ahmed
相关产品推荐
相关产品推荐

