Я делал что-то подобное раньше, но с авторизацией OAuth. По сути, у вас есть RestAdapter, инициализированный с помощью RequestInterceptor, который добавляет файл cookie сеанса к каждому запросу. RequestInterceptor получает новый файл cookie сеанса каждый раз при авторизации сеанса.
В приведенном ниже примере кода используется следующее определение интерфейса Retrofit REST:
interface ApiService {
@GET("/examples/v1/example")
Observable<Example> getExample();
}
Перехватчик запросов просматривает каждый запрос REST и может добавлять заголовки, параметры запроса или изменять URL-адрес. В этом примере предполагается, что файл cookie добавляется в качестве заголовка 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);
}
}
Это SessionService, на который вы ссылались. Он отвечает за сетевой запрос, который авторизует/обновляет файл 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");
}
}
Класс RestService обертывает интерфейс Retrofit, так что логика повторения запроса может быть добавлена к каждому Retrofit Observable.
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));
}
}
Приведенная ниже логика повторения будет использовать SessionService для обновления файла cookie сеанса, а затем повторить неудачные запросы REST, если файл cookie сеанса, отправленный на сервер, возвращает ошибку HTTP Unauthorized (401).
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);
}
});
}
}
Код инициализации клиента будет выглядеть примерно так:
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);
Затем получите наблюдаемый REST из RestService и подпишитесь на него, чтобы запустить сетевой запрос.
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.
}
});
person
kjones
schedule
28.08.2014