我有一个应用程序需要会话(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)));
答案 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
库)完成。