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[COROUTINE_CONTEXT_ATTRIBUTE] as CoroutineContext?
- return mono(context ?: Dispatchers.Unconfined) {
- filter(exchange, object : CoWebFilterChain {
- override suspend fun filter(exchange: ServerWebExchange) {
- exchange.attributes[COROUTINE_CONTEXT_ATTRIBUTE] = currentCoroutineContext().minusKey(Job.Key)
- chain.filter(exchange).awaitSingleOrNull()
- }
- })}.then()
- }
- /**
- * Process the Web request and (optionally) delegate to the next
- * [WebFilter] through the given [WebFilterChain].
- * @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 [ServerWebExchange] attribute that contains the
- * [kotlin.coroutines.CoroutineContext] to be passed to the
- * [org.springframework.web.reactive.result.method.InvocableHandlerMethod].
- */
- @JvmField
- val COROUTINE_CONTEXT_ATTRIBUTE = CoWebFilter::class.java.getName() + ".context"
- }
- }
- /**
- * Kotlin-specific adaption of [WebFilterChain] that allows for coroutines.
- *
- * @author Arjen Poutsma
- * @since 6.0.5
- */
- interface CoWebFilterChain {
- /**
- * Delegate to the next [WebFilter] 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方法,还不会生效。必须满足以下两个条件才可以生效
异常处理器
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 源码解析
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |