使用 RxJava 时如何重试对 HTTP 错误 (401) 的 Retrofit 调用? [英] How to retry Retrofit call on HTTP errors (401) when using RxJava?

查看:173
本文介绍了使用 RxJava 时如何重试对 HTTP 错误 (401) 的 Retrofit 调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我当前的 Android 应用程序正在使用 Retrofit(2.4.0)RxJava(2.1.16) 来执行我的 Web 服务调用.

My current Android Application is employing Retrofit(2.4.0) and RxJava(2.1.16) to execute my Web Service calls.

我使用 Google SignIn 进行用户身份验证.

Im using Google SignIn for my User Authentication.

我希望我的 Retrofit 调用能够检测 HTTP 401(未经授权)并尝试使用 Google Signin 静默登录然后重试 Retrofit 调用.

I want my Retrofit calls to detect HTTP 401 (UNAUTHORIZED) and attempt to Silently Login with Google Signin then retry the Retrofit call.

我的改造调用类似于这个

My retrofit calls resemble this

@Headers(HEADER_ACCEPT_JSON)
@GET("resources")
Observable<Response<String>> getResources(@Header(HEADER_AUTHORIZATION) @NonNull final String authenticationToken, @QueryMap(encoded = true) @NonNull Map<String, Object> queryMap);



API_SERVICE.getResources(Login.getAuthorizationToken(), id)
                .subscribeOn(Schedulers.io())
                .subscribe(Network::manageResource, Network::handle));

通过谷歌搜索我可以看到只有当我的 RxJava 链中发生错误时才会触发 retry/retryWhen,但是 HTTP 401 错误不会引发这种情况.

From googling I can see that retry/retryWhen will only be triggered when an error occurs in my RxJava chain, however HTTP 401 errors are not going to raise this condition.

作为 RxJava 的新手,我如何检测我的 HTTP 401 代码和..

As a newbie to RxJava how can I detect my HTTP 401 code and..

a).执行 Google SignIn 静默登录

a). Execute Google SignIn Silent login

b).静默登录完成 OK,重试我的 API 调用?

b). Silent login completes OK, retry my API call?

更新

我已经接近以下代码

@Headers(HEADER_ACCEPT_JSON)
@GET("resources")
Single<Response<String>> getResources(@Header(HEADER_AUTHORIZATION) @NonNull final String authenticationToken, @QueryMap(encoded = true) @NonNull Map<String, Object> queryMap);



API_SERVICE.getResources(Login.getAuthorizationToken(), id)
  .subscribeOn(Schedulers.io())
  .flatMap(new Function<Response<Article>,                                           
 SingleSource<Response<Article>>>() {
                        @Override
                        public SingleSource<Response<Article>> apply(final Response<Article> response) {
                            Log.d(TAG, "apply() called with: response = [" + response + "]");
                            if (response.isSuccessful()) {
                                return Single.just(response);
                            } else {
                                return Single.error(new RuntimeException());
                            }
                        }
                    })
                    .retryWhen(errors -> errors.take(1).flatMap(new Function<Throwable, Publisher<?>>() {
                        @Override
                        public Publisher<?> apply(final Throwable throwable) {
                            Log.d(TAG, "apply() called with: throwable = [" + throwable + "]");
                            Login.loginSilently().subscribe();

                            return Flowable.just("DELAY").delay(10, TimeUnit.SECONDS);
                        }
                    }))
                        .subscribe(Network::manageResource, Network::handle));

我不喜欢 Flowable.just("DELAY").delay() 调用,即使我现在捕获异常并在 OK 中静默登录,我也收到此异常

I do not like the Flowable.just("DELAY").delay() call and also even though I am now catching the exception and silently login in OK I get this exception

09-10 16:39:29.878 7651-7718/research.android E/Network: handle: 
    java.util.NoSuchElementException
        at io.reactivex.internal.operators.flowable.FlowableSingleSingle$SingleElementSubscriber.onComplete(FlowableSingleSingle.java:116)
        at io.reactivex.subscribers.SerializedSubscriber.onComplete(SerializedSubscriber.java:168)
        at io.reactivex.internal.operators.flowable.FlowableRepeatWhen$WhenReceiver.onComplete(FlowableRepeatWhen.java:119)
        at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.drainLoop(FlowableFlatMap.java:426)
        at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.drain(FlowableFlatMap.java:366)
        at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onComplete(FlowableFlatMap.java:673)
        at io.reactivex.subscribers.SerializedSubscriber.onComplete(SerializedSubscriber.java:168)
        at io.reactivex.internal.operators.flowable.FlowableDelay$DelaySubscriber$OnComplete.run(FlowableDelay.java:139)
        at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
        at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)
09-10 16:39:29.878 7651-7678/research.android  D/OkHttp: <-- HTTP FAILED: java.io.IOException: Canceled

如何获得重试时间以等待silentLogin 完成?

How can I get the retrywhen to wait for the silentLogin to complete?

导致 NoSuchElementException 的原因是什么?

Whats causing the NoSuchElementException?

推荐答案

据我所知,如果您的错误代码 > 300 那么 onError() 将使用 Throwable 调用,它可以转换为HttpException 从那里你可以得到服务器返回的错误代码,然后你就可以调用其他函数来进行一些静默调用"

As far as I remember if you have error code > 300 then onError() will be called with Throwable which can ba cast to HttpException from where you can get error code returned by server so then you can call other function to make some "silent call"

这篇关于使用 RxJava 时如何重试对 HTTP 错误 (401) 的 Retrofit 调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆