实现重试时的逻辑

时间:2015-05-28 21:57:48

标签: android session retrofit rx-java

我有一个应用程序需要会话(cookie)来处理网络电话。我正在使用Retrofit+RxJava。但是,会话可能会过期(使用401 Unauthorized状态进行Retrofit错误)并且我想重新进行身份验证(获取新的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)));

3 个答案:

答案 0 :(得分:8)

虽然Integer x1 = 5; // created through boxing Integer x2 = 5; Integer x3 = new Integer(5); // no boxing Integer x4 = new Integer(5); if (x1 == x2) System.out.println("Same object"); //prints if (x3 == x4) System.out.println("Same object"); //doesn't print 可能是针对此特定问题的更好解决方案,但问题明确要求使用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); } } }); } }) ,则不会再次调用getCookies。这只会重新订阅相同的retry,但在创建Observable之前调用getCookies。所以我认为你必须在[{1}}中包含源Observable的创建。

答案 1 :(得分:4)

使用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);
    }
  }
}

请记住同步您的身份验证进程代码,以便两个并发请求不会同时调用它。

答案 2 :(得分:0)

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

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