【问题标题】:Implement retryWhen logic实现 retryWhen 逻辑
【发布时间】:2016-02-16 11:17:53
【问题描述】:

我有一个需要会话(cookies)来处理网络调用的应用程序。我使用Retrofit+RxJava。但是,会话可能会过期(带有 401 未授权状态的改造错误),我想重新验证(以获取新的 cookie)并在这种情况下重试之前的调用。我将如何使用RxJava

我的例子:

getServerApi().getDialogs(offset, getCookies())
     .subscribeOn(Schedulers.newThread())
     .observeOn(AndroidSchedulers.mainThread())
     .retryWhen(observable -> {...}) // Need some logic
     .subscribe(dialogsEnvelope -> getView().setDialogs(dialogsEnvelope),
                throwable -> getView().setError(processFail(throwable)));

【问题讨论】:

  • 如果会话过期并且您需要重试,您是否会收到某种服务器响应来表明这一点(例如带有"success" : false 的 JSON)或者您只是一个RetrofitError
  • @david.mihola,更新了我的问题。我得到 401 Unauthorized(出现 Retorfit 错误)。
  • 我想我有一个想法,但我想在发布之前尝试一下......

标签: android session retrofit rx-java


【解决方案1】:

虽然Interceptor 可能是解决此特定问题的更好解决方案,但该问题专门要求使用retryWhen 提供解决方案,因此这是一种方法:

retryWhen(new Func1<Observable<Throwable>, Observable<?>>(){

    @Override
    public void Observable<?> call(Observable<Throwable>> attempts) {
        return attempts.flatMap(new Func1<Throwable, Observable<?>>() {

            @Override
            public Observable<?> call(Throwable throwable) {
                 if (throwable instanceof RetrofitError) {
                     RetrofitError retrofitError = (RetrofitError) throwable;
                     if (retrofitError.getKind() == RetrofitError.Kind.HTTP && retrofitError.getResponse().getStatus() == 401) {
                         // this is the error we care about - to trigger a retry we need to emit anything other than onError or onCompleted
                         return Observable.just(new Object());
                     } else {
                         // some other kind of error: just pass it along and don't retry
                         return Observable.error(throwable);
                     }
                 } else {
                     // some other kind of error: just pass it along and don't retry
                     return Observable.error(throwable);
                 }
             }
        });
    }
})

但是,在简单的retry 的情况下,您的getCookies 不会被再次调用。这只会重新订阅相同的Observable,但在创建Observable 之前调用了getCookies。因此,我认为您必须将源 Observable 的创建包装在 defer 中。

【讨论】:

  • 谢谢,我试试看!
  • 在这个例子中retry 也可以...为您保存一个平面地图。
【解决方案2】:

使用 OkHttp 极其强大的Interceptor

public class RecoverInterceptor implements Interceptor {
  String getAuth() {
    // check if we have auth, if not, authorize
    return "Bearer ...";
  }

  void clearAuth() {
    // clear everything
  }

  @Override public Response intercept(Chain chain) throws IOException {
    final Request request = chain.request();
    if (request.urlString().startsWith("MY ENDPOINT")) {
      final Request signed = request.newBuilder()
          .header("Authorization", getAuth())
          .build();
      final Response response = chain.proceed(signed);
      if (response.code() == 401) {
        clearAuth();
        return intercept(chain);
      } else {
        return response;
      }
    } else {
      return chain.proceed(request);
    }
  }
}

记得同步你的认证过程代码,这样两个并发请求就不会同时调用它。

【讨论】:

    【解决方案3】:

    在浏览 Internet 以找到正确答案时 - 我发现 this cool gist 描述了如何在 OkHttp Interceptor 的帮助下刷新 OAuth 令牌(类似于接受的答案,但更完整) .

    它与 RxJava 无关,但对我来说它更容易接受,因为我不必用 retryWith 逻辑包装每个 Observable - 一切都在较低级别完成(OkHttp 库)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-19
      • 2020-11-09
      • 2019-09-29
      • 1970-01-01
      相关资源
      最近更新 更多