【发布时间】:2015-01-11 04:57:57
【问题描述】:
我是 RxJava 的新手,但我正在尝试使用 Retrofit 框架和 RxJava 实现一个 API。 在服务器端,有一个授权服务处理用户的会话,如果用户的操作有一些延迟,服务器会中断他的会话。之后,用户必须再次登录才能执行新的 API 调用。坏事是 - 服务器总是返回 HTTP 代码 200 并且关于过期的通知使用一些带有过期代码的自定义 JSON 响应,因此 RxJava 在 onNext 操作期间不会触发异常,因为 RxJava 认为该请求已成功传递。
问题是:如何实现正确的流程来处理自定义 API 异常,例如过期和在其他请求(在我的情况下是重新登录)之后重试失败的请求?
类似这样的:
- 应用程序->登录()
- 服务器 -> { 代码:0, ... }
- 应用程序-> getUsers()
- 服务器 -> { 代码:0, ... }
- ------- 30 分钟后 -------
- 应用程序->getPicture()
- server -> { code:99, ... } // 会话过期,用户未授权
- 应用程序->登录()
- 服务器 -> { 代码:0, ... }
- 应用程序->getPicture()
- 服务器 -> { 代码:0, ... }
我正在考虑这样的事情,但没有成功:
Observable.create(new Observable.OnSubscribe<BackendResponse<String>>() {
@Override
public void call(Subscriber<? super Response<String>> subscriber) {
try {
Response<String> response;
subscriber.onNext(response = getInterface().getUsers());
if (response != null) {
response.checkData(); // throws ServerException in case of code != 0
}
subscriber.onCompleted();
} catch (Exception e) {
subscriber.onError(e);
}
}
}).subscribeOn(Schedulers.io()).retryWhen(new RetryWithSessionRefresh(new SessionService())).subscribe();
而 RetryWithSessionRefresh 是:
public class RetryWithSessionRefresh implements
Func1<Observable<? extends Notification<?>>, Observable<?>> {
private final SessionService sessionSerivce;
public RetryWithSessionRefresh(SessionService sessionSerivce) {
this.sessionSerivce = sessionSerivce;
}
@Override
public Observable<?> call(Observable<? extends Notification<?>> attempts) {
return attempts
.flatMap(new Func1<Notification<?>, Observable<?>>() {
@Override
public Observable<?> call(final Notification notification) {
final Throwable throwable = notification.getThrowable();
if (throwable instanceof ServerException) {
final ServerException backendException = (ServerException) throwable;
if (backendException.getBackendErrorCode() == Response.AUTHORIZATION_FAILED) {
return sessionSerivce
.observeSessionToken()
.doOnNext(new Action1<TokenCallback>() {
@Override
public void call(TokenCallback token) {
if (token != null) {
DataHolder.getInstance().setAuthToken(token.getToken());
}
}
})
.doOnError(new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
DataHolder.getInstance().setAuthToken("");
}
});
}
}
return Observable.error(notification.getThrowable());
}
});
}
【问题讨论】: