che ho fatto qualcosa di simile a questo prima, ma con autorizzazione OAuth. Fondamentalmente, hai un RestAdapter inizializzato con un RequestInterceptor che aggiunge il cookie di sessione ad ogni richiesta. RequestInterceptor riceve un nuovo cookie di sessione ogni volta che una sessione è autorizzata.
la seguente definizione di interfaccia Retrofit resto è usato nel codice di esempio riportato di seguito:
interface ApiService {
@GET("/examples/v1/example")
Observable<Example> getExample();
}
La richiesta intercettore ottiene uno sguardo a ogni richiesta REST e può aggiungere intestazioni, parametri di query o può modificare l'URL. Questo esempio assume che il cookie sia aggiunto come intestazione 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);
}
}
Questo è il SessionService a cui si è alluso. È responsabilità di effettuare la richiesta di rete che autorizza/aggiorna il cookie di sessione.
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");
}
}
La classe RestService avvolge l'interfaccia retrofit in modo che la logica tentativo richiesta può essere aggiunto a ciascuna retrofit osservabili.
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));
}
}
La logica dei tentativi di seguito utilizzerà il SessionService per aggiornare il cookie di sessione e riprovare le richieste REST fallite se il cookie di sessione inviato al server restituisce un non autorizzato (401) errore HTTP.
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);
}
});
}
}
codice di inizializzazione client sarà simile a questo:
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);
di riposare poi osservabile dal RestService e abbonarsi ad esso per dare il via alla richiesta di rete.
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.
}
});
In realtà sembra abbastanza pulito. Grazie! Errore – midnight
: tipi incompatibili: RetryWithSessionRefresh non può essere convertito in Func1 super osservabile estende Throwable> ,? estende Observable >> in realtà funziona solo con la sovversione di RxJava da netflix – desgraci
@desgraci L'API retryWhen() è stata modificata in RxJava 1.0. Ho aggiornato la risposta per la compatibilità 1.0+. – kjones