首页 > 解决方案 > 在 RxJava2 中捕获错误并返回新类型

问题描述

我有一个流:

val symbols: Single<List<Symbol>>

现在我想使用 map() 将流转换为 UI 状态:

private fun cool(): Single<SymbolContract.State> =
    symbols.map { SymbolContract.State.Symbols(it) }

我想做的是在上游symbols单上捕获一个错误,这样我就可以捕获任何错误然后返回SymbolContract.State.GeneralError()

我想要类似 a 之类的onErrorMap()东西。不幸的是,穿上不起作用,因为它需要返回onErrorResumeItem一个.symbolsList<Symbol>

我可以想到一些丑陋的方法来做到这一点,但是最干净的方法是什么?

标签: javakotlinrx-javarx-java2reactivex

解决方案


我建议你使用全局处理错误。我给你一个样本,这样你就可以理解了。(它是 kotlin),您可以捕获任意数量的异常,其中一些是我的自定义异常。请记住,这个示例是关于 Reactive Webflux 的,但你明白了。其他人也会类似

@Configuration
class ExceptionTranslator {

    @Bean
    @Order(-1)
    fun handle(objectMapper: ObjectMapper): ErrorWebExceptionHandler {
        return ErrorWebExceptionHandler { exchange, ex ->
            if (exchange.response.isCommitted) {
                return@ErrorWebExceptionHandler Mono.error(ex)
            }

            val response = exchange.response
            response.statusCode = HttpStatus.INTERNAL_SERVER_ERROR
            response.headers.contentType = MediaType.APPLICATION_PROBLEM_JSON_UTF8

            val url: String

            var message = ex.message
            var params = mutableMapOf<String, Any>()

            when (ex) {
                is ParametricException -> {
                    url = ex.url
                    params = ex.params
                }
                is BaseException -> {
                    url = ex.url
                }
                is BadCredentialsException -> {
                    url = INVALID_CREDENTIAL_TYPE
                    message = ex.message ?: "Wrong Credentials"
                }
                is ConcurrencyFailureException -> {
                    url = INTERNAL_TYPE
                    message = ERR_CONCURRENCY_FAILURE
                }
                is MethodArgumentNotValidException -> {
                    val result = ex.bindingResult
                    val fieldErrors = result.fieldErrors.map {
                        FieldErrorVM(it.objectName, it.field, it.code ?: "Unknown")
                    }

                    url = CONSTRAINT_VIOLATION_TYPE
                    message = ERR_VALIDATION
                    params = Collections.singletonMap("errors", fieldErrors)
                }
                else -> url = INTERNAL_TYPE
            }

            if (ex is BaseException) {
                response.statusCode = HttpStatus.valueOf(ex.status.code())
            }

            val bytes = objectMapper.writeValueAsBytes(ProblemVM(url, message ?: "Internal Error", params))
            val buffer = response.bufferFactory().wrap(bytes)
            response.writeWith(Mono.just(buffer))
        }
    }

}

推荐阅读