实现重试时的逻辑

loc*_*ost 7 session android rx-java retrofit

我有一个应用程序,需要会话(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)));
Run Code Online (Sandbox Code Playgroud)

dav*_*ola 8

虽然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);
                 }
             }
        });
    }
})
Run Code Online (Sandbox Code Playgroud)

但是,getCookies在简单的情况下,不会再次调用retry.这只会重新订阅相同ObservablegetCookies在创建之前被调用Observable.所以我认为你必须将源的创建包装Observable在一个defer.


Ade*_*nov 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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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