本文介绍了改造/ Rxjava和基于会话的服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我实现基于会话的服务。所有的请求都用一个cookie会话参数,而这又是获取独立REST API进行订阅。所以基本的工作流程将得到会话cookie并继续查询服务。偶尔的cookie将过期,这将导致另一个会话cookie的请求。

I'm implementing session-based services. All requests have to be subscribed with a cookie session param, which in turn is retrieved with separate rest api. So the basic workflow would be to get the session cookie and proceed querying the services. Occasionally the cookie would expire and it would lead to another session cookie request.

我试图让客户code会议无关的,所以它不会担心维护会话,而是我希望它被隐藏在服务层。

I'm trying to make client code session-agnostic, so that it doesn't have to worry about maintaining session, but rather I want it to be hidden inside services layer.

您能否提供与改装/ RxJava 实施它的想法?我觉得 SessionService 已被所有其他服务进行封装,使他们可以查询它,只要它是必需的,但我不知道如何与改造的<$ C做$ C> RestAdapter.create

Can you suggest ideas on implementing it with Retrofit/RxJava? I think the SessionService has to be encapsulated by all other services, so that they can query it whenever it's required but I'm not sure how to do it with Retrofit's RestAdapter.create

推荐答案

我做与此类似,但之前与OAuth的授权东西。基本上,你有一个RequestInterceptor,增加了会话cookie每个请求初始化的RestAdapter。该RequestInterceptor得到一个新的会话Cookie的会话授权任何时候。

I've done something similar to this before but with OAuth authorization. Basically, you have a RestAdapter initialized with a RequestInterceptor that adds the session cookie to each request. The RequestInterceptor gets a new session cookie any time a session is authorized.

下面的改造REST接口定义是用在下面的例子中code:

The following Retrofit REST interface definition is used in the example code below:

interface ApiService {
    @GET("/examples/v1/example")
    Observable<Example> getExample();
}

请求拦截器得到一个偷看每个REST请求,并可以添加标题,查询参数或可修改URL。这个例子假设该cookie将被添加为HTTP头。

The Request interceptor gets a peek at each REST request and can add headers, query params or can modify the URL. This example assumes the cookie is added as an HTTP header.

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。

This is the SessionService you alluded to. It's responsibility is to make the network request that authorizes/refreshes the session 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类包装改造接口,以便请求重试逻辑可以被添加到每个改造可观察

The RestService class wraps the Retrofit interface so that request retry logic can be added to each 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未经授权(401)错误。

The retry logic below will use the SessionService to update the session cookie and then retry failed REST requests if the session cookie sent to the server returns an HTTP Unauthorized (401) error.

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);
                    }
                });
    }
}

客户端初始化code将类似于此:

Client initialization code will look similar to this:

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观察到的,并订阅它揭开序幕的网络请求。

Then get a REST observable from the RestService and subscribe to it to kick off the network request.

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.
            }
        });

这篇关于改造/ Rxjava和基于会话的服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 10:54