我已经做过类似的东西,在这之前,但与OAuth授权。基本上,您有一个使用RequestInterceptor初始化的RestAdapter,它将会话cookie添加到每个请求中。每次授权会话时,RequestInterceptor都会获取新的会话cookie。
以下改造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类包装改造接口,以便请求重试逻辑可以被添加到每个改造观察到。下面
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未经授权(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);
然后得到从RestService观察到一个REST和订阅它揭开序幕的网络请求。
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.
}
});
它实际上看起来很整齐。谢谢! – midnight 2014-08-29 06:58:16
错误:不兼容的类型:RetryWithSessionRefresh无法转换为Func1 <?超级可观察<?扩展Throwable>,?扩展Observable >>它实际上只适用于Netflix的RxJava版本 – desgraci 2015-06-25 20:12:00
@desgraci RxJava 1.0中的retryWhen()API已更改。我已经为1.0+兼容性更新了答案。 – kjones 2015-06-26 20:36:07