Robiłem coś podobnego do tego wcześniej, ale z autoryzacją OAuth. Zasadniczo masz Restartener zainicjalizowany za pomocą obiektu RequestInterceptor, który dodaje plik cookie sesji do każdego żądania. RequestInterceptor pobiera nowy plik cookie sesji za każdym razem, gdy sesja jest autoryzowana.
Poniższa definicja interfejsu Modernizacja reszta jest używany w przykładowym kodzie poniżej:
interface ApiService {
@GET("/examples/v1/example")
Observable<Example> getExample();
}
Żądanie przechwytujących dostaje okiem na każde żądanie REST i można dodać nagłówki, params zapytań lub można zmodyfikować URL. W tym przykładzie założono, że plik cookie jest dodawany jako nagłówek HTTP.
class CookieHeaderProvider implements RequestInterceptor {
private String sessionCookie = "";
public CookieHeaderProvider() {
}
public void setSesstionCookie(String sessionCookie) {
this.sessionCookie = sessionCookie;
}
@Override
public void intercept(RequestFacade requestFacade) {
requestFacade.addHeader("Set-Cookie", sessionCookie);
}
}
To jest usługa SessionServices, o której mówiliście. Odpowiedzialnością jest wykonanie żądania sieciowego, które autoryzuje/odświeża sesyjny plik cookie.
class SessionService {
// Modify contructor params to pass in anything needed
// to get the session cookie.
SessionService(...) {
}
public Observable<String> observeSessionCookie(...) {
// Modify to return an Observable that when subscribed to
// will make the network request to get the session cookie.
return Observable.just("Fake Session Cookie");
}
}
Klasa RestService owija modyfikacyjne interfejs logiczny, tak że żądanie ponownej próby mogą być dodawane do każdego Retrofit widoczne.
class RestService {
private final apiService;
private final sessionSerivce;
private final cookieHeaderProvider;
RestService(ApiService apiService,
SessionService sessionSerivce,
CookieHeaderProvider cookieHeaderProvider) {
this.apiService = apiService;
this.sessionSerivce = sessionSerivce;
this.cookieHeaderProvider = cookieHeaderProvider;
}
Observable<Example> observeExamples() {
// Return a Retrofit Observable modified with
// session retry logic.
return
apiService
.observeExamples()
.retryWhen(new RetryWithSessionRefresh(sessionSerivce, cookieHeaderProvider));
}
}
retry logika poniżej użyje SessionService zaktualizować cookie sesji i ponownie nieudane żądania odpoczynku, jeżeli ciasteczka sesji wysyłane do serwera HTTP zwraca Nieuprawnione (401) o błędzie.
public class RetryWithSessionRefresh implements
Func1<Observable<? extends Throwable>, Observable<?>> {
private final SessionService sessionSerivce;
private final CookieHeaderProvider cookieHeaderProvider;
public RetryWithSessionRefresh(SessionService sessionSerivce,
CookieHeaderProvider cookieHeaderProvider) {
this.sessionSerivce = sessionSerivce;
this.cookieHeaderProvider = cookieHeaderProvider;
}
@Override
public Observable<?> call(Observable<? extends Throwable> attempts) {
return attempts
.flatMap(new Func1<Throwable, Observable<?>>() {
public int retryCount = 0;
@Override
public Observable<?> call(final Throwable throwable) {
// Modify retry conditions to suit your needs. The following
// will retry 1 time if the error returned was an
// HTTP Unauthoried (401) response.
retryCount++;
if (retryCount <= 1 && throwable instanceof RetrofitError) {
final RetrofitError retrofitError = (RetrofitError) throwable;
if (!retrofitError.isNetworkError()
&& retrofitError.getResponse().getStatus() == HttpStatus.SC_UNAUTHORIZED) {
return sessionSerivce
.observeSessionCookie()
.doOnNext(new Action1<String>() {
@Override
public void call(String sessionCookie) {
// Update session cookie so that next
// retrofit request will use it.
cookieHeaderProvider.setSesstionCookie(sessionCookie);
}
})
.doOnError(new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
// Clear session cookie on error.
cookieHeaderProvider.setSesstionCookie("");
}
});
}
}
// No more retries. Pass the original
// Retrofit error through.
return Observable.error(throwable);
}
});
}
}
Client kod inicjalizacji będzie wyglądać podobnie do tego:
CookieHeaderProvider cookieHeaderProvider = new CookieHeaderProvider();
SessionService sessionSerivce = new SessionService();
ApiService apiService =
new RestAdapter.Builder()
.setEndpoint(...)
.setClient(...)
.setRequestInterceptor(cookieHeaderProvider)
.build()
.create(ApiService.class);
RestService restService =
new RestService(apiService, sessionSerivce, cookieHeaderProvider);
Następnie dostać odpocząć zaobserwowania z RestService i zapisać się do niej skopać żądanie sieciowe.
Observable<Example> exampleObservable =
restService
.observeExamples();
Subsctiption subscription =
exampleObservable
.subscribe(new Observer<Example>() {
void onNext(Example example) {
// Do stuff with example
}
void onCompleted() {
// All done.
}
void onError(Throwalbe e) {
// All API errors will end up here.
}
});
Wygląda całkiem nieźle. Dzięki! – midnight
error: niezgodne typy: RetryWithSessionRefresh nie można przekonwertować na Func1 super obserwowalne extends Throwable> ,? extends Observable >> faktycznie działa tylko z subversion RxJava z netflix – desgraci
@desgraci Interfejs API retryWhen() został zmieniony w RxJava 1.0. Zaktualizowałem odpowiedź na zgodność z wersją 1.0+. – kjones