RxJava:如何在同时发送多个请求时刷新令牌?

时间:2017-01-24 14:19:05

标签: android oauth-2.0 rx-java retrofit2 refresh-token

我有一个使用OAuth2进行身份验证的应用,并使用Retrofit从RESTful服务中获取数据。现在,我有令牌检索和刷新并运行。令牌会像这样刷新(调度程序省略):

// Each Retrofit call observable is "wrapper" using this method
protected <T> Observable<T> wrap(@NonNull final Observable<T> page) {
    return authenticate()
        .concatMap(token -> page)
        .onErrorResumeNext(throwable -> {
            Log.w(TAG, "wrap: ErrorResumeNext", throwable);
            return refreshAccessToken()
                .flatMap(accessToken -> page);
        }));
}

// Retrieves the access token if necessary
Observable<AccessToken> authenticate() {
    // Already have token
    if(accessToken != null) return Observable.just(accessToken);
    // No token yet, fetch it
    return api.getAccessToken(...);
}

// Refreshes the token
Observable<AccessToken> refreshAccessToken() {
    return api.refreshToken(...);
}

这样可行,但在某些情况下,会同时发送多个请求,并且它们都会调用刷新过程 - 基本上我的应用程序最终会刷新令牌的次数与此时请求的次数相同。

所以,问题是:我如何确保在需要刷新令牌时,无论有多少正在进行的请求需要刷新令牌,它只会执行一次?我可以以某种方式提出其他请求&#34;等待&#34;直到第一个请求成功调用并检索新令牌?

1 个答案:

答案 0 :(得分:2)

我们使用hot observable来完成此行为,以刷新令牌并为所有未通过身份验证的请求提供对其实例的访问。

使用share运算符将基本的冷可观察性转换为将令牌刷新为热点,因此每个其他订阅者共享其结果。一旦请求返回,所有等待的观察者都会得到通知,并且在那一刻(在share()之前,它在doOnUnsubscribe之前到达[assembly: AssemblyFileVersion("1.0.0.0")] 的回调),销毁刷新的可观察实例,以便下一个订阅者创建新的一个。所有这些都可以通过单例模式轻松实现,您可以将刷新的observable包装到单件包装器类中,并通过getInstance()请求它。如果没有请求 - 实例为null - getInstance应该创建一个新的。

您需要注意一些其他事项,例如,在刷新期间出错并使令牌无效,但这些是基础知识。

我现在没有太多时间详细说明这个问题,但是如果你自己实现这个问题会遇到一些麻烦,请留言,我会在明天发布一些代码示例。没有背景,它们就没有多大意义。