У меня есть следующие конечные точки в REST API:
public interface AutomoticzAPI {
@POST("/api/beacon_auth/login")
Single<LoginResponse> login(@Body LoginRequest request);
@GET("/api/system/ws_devices")
Single<WSDevicesResponse> wsDeviceList(@Header("Authorization") String tokenHeader);
}
Когда я вызываю login
конечную точку, в ответ я получаю токен доступа, который я сохраняю в ClientSession
объект-держатель. Позже я смогу извлечь токен из ClientSession
для вызова защищенных ресурсов сервера:
api.login(ClientSession.getInstance().getLoginRequest(login, password))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(loginResponse -> {
String accessToken = loginResponse.getAccessToken();
ClientSession.getInstance().setAccessToken(accessToken);
view.onLoginSuccess();
}, throwable -> {
RetrofitException exception = (RetrofitException) throwable;
if (exception.getKind().equals(RetrofitException.Kind.HTTP)){
view.onLoginFailed(exception.getMessage());
} else if(exception.getKind().equals(RetrofitException.Kind.NETWORK))
{
view.onLoginFailed("Network error...");
} else {
view.onLoginFailed("Unknown error occurred...");
}
});
Когда я звоню на конечную точку wsDeviceList
, сервер может вернуть код ответа 401 HTTP и тело json с кодом ошибки и сообщением:
{
"code": "EXPIRED-TOKEN",
"message": "Token expired"
}
Если это произойдет, я хочу еще раз позвонить в конечную точку входа в систему, чтобы получить новый токен доступа. Вот мой код:
ClientSession clientSession = ClientSession.getInstance();
String token = "Bearer "+clientSession.getAccessToken();
String url = ClientSession.getInstance().getUrl();
AutomoticzAPI api = NetworkManager.getApiClient(url);
api.wsDeviceList(token)
.retryWhen(throwableFlowable -> throwableFlowable.flatMap(
new Function<Throwable, Publisher<?>>() {
@Override
public Publisher<?> apply(Throwable throwable) throws Exception {
RetrofitException exception = (RetrofitException) throwable;
if (exception.isUnauthorizedError()){
return relogin(api, clientSession.getLoginRequest());
}
return (Publisher<?>) throwable;
}
}
))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(wsDevicesResponse -> {
view.onDeviceListLoaded(wsDevicesResponse.getWsdevices());
}, throwable -> {
RetrofitException exception = (RetrofitException) throwable;
view.onError(exception);
});
}
public Publisher<?> relogin(AutomoticzAPI api, LoginRequest loginRequest){
return (Publisher<?>) api.login(loginRequest)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(loginResponse -> {
String accessToken = loginResponse.getAccessToken();
ClientSession.getInstance().setAccessToken(accessToken);
}, throwable -> {
RetrofitException exception = (RetrofitException) throwable;
view.onError(exception);
});
}
Но когда запускается метод relogin
, моя программа падает.
Я не опытный в RxJava и, вероятно, делаю это неправильно. Как я могу вспомнить login
, чтобы обновить токен доступа, а затем снова вызвать wsDeviceList
?