I send a login request to server with retrofit 2.0, and server return to the client session token, wich I must use in other requests, but this token has limited life-time, and when it is expire server returns HTTP error 401.
I try make re-logon, after getting this error, with help a next code:
holder.getApi(GuideProfileApi.class)
.getProfile(String.valueOf(holder.getServerId()), holder.getServerToken())
.subscribeOn(Schedulers.io())
.retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(Throwable throwable) throws Exception {
if (throwable instanceof HttpException && ((HttpException)throwable).code() == 401) {
RegistryLoginResult loginResult = holder.login().blockingSingle();
return holder.getApi(GuideProfileApi.class)
.getProfile(String.valueOf(loginResult.getUserId()), loginResult.getSessionToken());
}
return Observable.error(throwable);
}
});
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<ProfileResult>() {
@Override
public void accept(ProfileResult profileResult) throws Exception {
Log.d("Result", profileResult.toString());
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
Log.e("Result", throwable.getLocalizedMessage());
}
});
And retry request is sent, but parameters of request are same as in incorrect request (before re-login). How I can change parameters of the request before sending it again?
You can use retryWhen
, but the problem is that your retryWhen retry the same observable object that you create in lazy moment.
Your solution here is use the operator defer
to get the host(), since defer it´s not creating the observable when you define it but when it´s consumed by the subscribed.
Observable.defer(()-> holder.getApi(GuideProfileApi.class)
.getProfile(String.valueOf(holder.getServerId()),holder.getServerToken()))
.subscribeOn(Schedulers.io())
.retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(Throwable throwable) throws Exception {
if (throwable instanceof HttpException && ((HttpException)throwable).code() == 401) {
RegistryLoginResult loginResult = holder.login().blockingSingle();
return holder.getApi(GuideProfileApi.class)
.getProfile(String.valueOf(loginResult.getUserId()), loginResult.getSessionToken());
}
return Observable.error(throwable);
}
});
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<ProfileResult>() {
@Override
public void accept(ProfileResult profileResult) throws Exception {
Log.d("Result", profileResult.toString());
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
Log.e("Result", throwable.getLocalizedMessage());
}
});
You can see some examples of retry here https://github.com/politrons/reactive/blob/master/src/test/java/rx/observables/errors/ObservableExceptions.java
You're using the wrong operator. retryWhen
will retry your original observable if it encounters an error. What you need is onErrorResumeNext
. Something like
holder.getApi(GuideProfileApi.class)
.getProfile(String.valueOf(holder.getServerId()), holder.getServerToken())
.subscribeOn(Schedulers.io())
.onErrorResumeNext(new Function<Throwable, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(Throwable throwable) {
if (throwable instanceof HttpException && ((HttpException)throwable).code() == 401) {
RegistryLoginResult loginResult = holder.login().blockingSingle();
return holder.getApi(GuideProfileApi.class)
.getProfile(String.valueOf(loginResult.getUserId()), loginResult.getSessionToken());
}
return Observable.error(throwable);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<ProfileResult>() {
@Override
public void accept(ProfileResult profileResult) throws Exception {
Log.d("Result", profileResult.toString());
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
Log.e("Result", throwable.getLocalizedMessage());
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With