Как обработать ответ 400 в rxjava2

Я борюсь с правильной обработкой исключений в RxJava2. Я пытаюсь обновить свой токен внутри перехватчика OkHttp3 следующим образом:

tokenRepository.refreshToken(authStateManager.current.refreshToken!!)
                        .doOnError {
                            Log.w(TAG, "Could not obtain new access token.")

                            authStateManager.signOut()
                        }
                        .subscribe { tokenResponse ->
                            Log.d(TAG, "Obtained new access token: " + tokenResponse.toString())

                            authStateManager.updateAfterTokenResponse(TokenResponse.jsonDeserialize(tokenResponse.toString()), null)

                            token = authStateManager.current.accessToken
                        }

Он отлично работает, если токен обновления действителен и запрос возвращает 200. Но если токен обновления недействителен и я получаю код ошибки (например, 400), блок doOnError выполняется, но затем он переходит к блоку подписки, где следующий выбрасывается исключение:

retrofit2.adapter.rxjava2.HttpException: HTTP 400 
        at retrofit2.adapter.rxjava2.BodyObservable$BodyObserver.onNext(BodyObservable.java:54)
        at retrofit2.adapter.rxjava2.BodyObservable$BodyObserver.onNext(BodyObservable.java:37)
...

Я пробовал использовать onErrorReturn и onErrorResumeNext, но я хотел бы полностью пропустить блок подписки (если возникла ошибка, просто выйдите из системы и не пытайтесь ничего делать). Является ли это возможным? Метод refreshToken возвращает тип ответа Single<JsonObject>.

0
0
518
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Разве вы не можете использовать onError по подписке? Мне нравится использовать для этого RxKotlin. Например, я могу сделать следующее:

.subscribeBy(onSuccess = {
     // do Something in on success
}, onError = {
     // do something in onError
})

Итак, в вашем случае это может быть что-то вроде:

tokenRepository.refreshToken(authStateManager.current.refreshToken!!)
    .subscribeBy(onSuccess = {
        Log.d(TAG, "Obtained new access token: " + it.toString())
        authStateManager.updateAfterTokenResponse(TokenResponse.jsonDeserialize(it.toString()), null)
        token = authStateManager.current.accessToken
    }, onError = {
        Log.w(TAG, "Could not obtain new access token.")
        // the variable "it" here is a throwable which means you can determine if it's a RetrofitException and what status code is returned
    })

Однако, если вы не хотите использовать RxKotlin, вы можете обрабатывать свои подписки Rx следующим образом в Kotlin:

.subscribe({ Log.d(TAG, "Obtained new access token: " + it.toString()) },
           { Log.e(TAG, "Error is ${it.message}") })

Вы можете обработать ошибку во второй части функции, в которой используется Log.e.

Я не уверен, как это сделать в моем сценарии. Не могли бы вы объяснить в моем случае, как изменить моего подписчика?

Smajl 11.04.2018 12:20

Да, конечно. Прежде всего, добавьте зависимость RxKotlin в свою сборку gradle. Затем измените раздел подписки на subscribeBy. Я изменю свой ответ выше.

blackpanther 11.04.2018 12:21

Я хотел бы придерживаться RxJava ... Мне пришлось бы изменить большую часть моего приложения, и я уверен, что это можно сделать без других зависимостей.

Smajl 11.04.2018 12:27

Да, вы можете, если вы замените subscribeBy на subscribe (вам придется удалить слова onSuccess и onError, но принципы и структура такие же. Кроме того, RxKotlin не является перезаписью RxJava - это очень небольшая библиотека, в которой есть небольшие функции, которые делают написание кода RxJava более читабельным в Kotlin - потому что, в конце концов, RxJava написан для Java, а не для Kotlin

blackpanther 11.04.2018 12:29

@Smajl Я добавил немного, кроме внизу ответа, который использует чистый RxJava в Kotlin

blackpanther 11.04.2018 12:42

У меня была такая же проблема, но я исправил ее сейчас. Я не знаю, правильно ли мое объяснение, но похоже, что doOnError не обрабатывает исключение.

Вам нужно использовать метод subscribe(), который принимает onErrorConsumer в качестве параметра и обрабатывать ошибку там:

subscribe(Consumer<? super T> onSuccess, Consumer<? super Throwable> onError)

На Java это выглядело бы так:

.subscribe(tokenResponse -> {
                Log.d(TAG, "Obtained new access token: " + tokenResponse.toString());
                authStateManager.updateAfterTokenResponse(TokenResponse.jsonDeserialize(tokenResponse.toString()), null);
                token = authStateManager.current.accessToken;
            }, throwable -> {
                Log.w(TAG, "Could not obtain new access token.");
                authStateManager.signOut();
            }));

Другие вопросы по теме