厨浴 发表于 2025-6-8 23:52:17

SpringBoot3 WebFlux 拦截器 和 全局异常处理器

SpringBoot3 WebFlux 拦截器 和 全局异常处理器

一、拦截器

org.springframework.web.server.CoWebFilter其父类是org.springframework.web.server.WebFilter
webflux 的 拦截器 就像 Servlet 的 Filter 较为原始. 所以Filter咋使用。WebFilter就咋使用。而CoWebFilter是协程环境的Kotlin专用WebFilter,其内部使用mono将Mono转换为了kotlin的挂起函数。
CoWebFilter.kt
abstract class CoWebFilter : WebFilter {

        final override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
                val context = exchange.attributes as CoroutineContext?
                return mono(context ?: Dispatchers.Unconfined) {
                        filter(exchange, object : CoWebFilterChain {
                                override suspend fun filter(exchange: ServerWebExchange) {
                                        exchange.attributes = currentCoroutineContext().minusKey(Job.Key)
                                        chain.filter(exchange).awaitSingleOrNull()
                                }
                        })}.then()
        }

        /**
       * Process the Web request and (optionally) delegate to the next
       * through the given .
       * @param exchange the current server exchange
       * @param chain provides a way to delegate to the next filter
       */
        protected abstract suspend fun filter(exchange: ServerWebExchange, chain: CoWebFilterChain)

        companion object {

                /**
               * Name of the attribute that contains the
               * to be passed to the
               * .
               */
                @JvmField
                val COROUTINE_CONTEXT_ATTRIBUTE = CoWebFilter::class.java.getName() + ".context"
        }

}

/**
* Kotlin-specific adaption of that allows for coroutines.
*
* @author Arjen Poutsma
* @since 6.0.5
*/
interface CoWebFilterChain {

        /**
       * Delegate to the next in the chain.
       * @param exchange the current server exchange
       */
        suspend fun filter(exchange: ServerWebExchange)

}源码分析:
代码非常简单哈,使用CoWebFilter只需要集成并且实现filter方法即可。
放行

放行只需要调用chain.filter(exchange)即可。并且其可以传递CoroutineContext上下文对象,类似于ThreadLocal.
拦截

val defaultMessage = "token is invalid"
exchange.response.apply {
    statusCode = HttpStatus.UNAUTHORIZED
    headers.contentType = MediaType.APPLICATION_JSON
    val result: edu.tyut.spring_boot_ssm.bean.Result<Boolean> = edu.tyut.spring_boot_ssm.bean.Result.failure(message = defaultMessage, data = false)
    val resultJson: String = objectMapper.writeValueAsString(result)
    val buffer: DataBuffer = bufferFactory().wrap(resultJson.toByteArray(charset = Charsets.UTF_8))
    writeWith(Mono.just<DataBuffer>(buffer)).awaitSingleOrNull()
}.setComplete().awaitSingleOrNull()拦截也是比较简单的的直接在filter方法中调用以上方法即可
work

实现了filter方法,还不会生效。必须满足以下两个条件才可以生效

[*]webflux环境
[*]注入bean容器
异常处理器

org.springframework.web.server.CoWebExceptionHandler#CoWebExceptionHandler
这个类是github社区的贡献的。
使用


[*]实现CoWebExceptionHandler
[*]重写coHandle方法
[*]注入容器
[*]提高优先级
案例

GlobalExceptionHandler.kt
@Order(value = -2)
@Component
internal final class GlobalExceptionHandler(
) : CoWebExceptionHandler() {

    private final val logger: Logger = LoggerFactory.getLogger(this.javaClass)

    override suspend fun coHandle(exchange: ServerWebExchange, ex: Throwable) {
      when (ex) {
            is WebExchangeBindException -> {
                this.handlerBindException(exchange = exchange, ex = ex)
            }
            else -> {
                this.handlerOtherException(exchange = exchange, ex = ex)
            }
      }
    }
}TODO

WebFilter 源码解析

WebExceptionHandler 源码解析


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: SpringBoot3 WebFlux 拦截器 和 全局异常处理器