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

5

我有一个使用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(...);
}

这个方法是可行的,但在某些情况下,会同时发送多个请求,它们都会触发刷新过程——基本上我的应用程序会根据那一刻的请求数量刷新令牌的次数。

因此,问题是:如何确保仅在需要刷新令牌时执行一次刷新操作,而不管有多少正在进行的请求需要刷新令牌?我是否可以使其他请求“等待”,直到第一个请求成功调用并检索到新令牌?

1个回答

3
我们使用热可观察对象来刷新令牌并为所有未能通过身份验证的请求提供访问其实例的行为。使用share操作符将用于刷新令牌的基本冷可观察对象转换为热可观察对象,以便每个其他订阅者共享其结果。一旦请求返回,所有等待的观察者都会被通知,在这一时刻(在操作符链中,它出现在share()之前,成为doOnUnsubscribe的回调函数),销毁刷新可观察对象实例,以便下一个订阅者将创建新的实例。所有这些都可以通过单例模式轻松实现,您可以将刷新可观察对象包装到单例包装类中,并通过getInstance()进行请求。如果没有正在进行的请求,则该实例为空--getInstance应该创建一个新实例。
还有一些其他需要注意的问题,例如刷新期间的错误和无效令牌,但这些是基础知识。
我现在没有太多时间详细说明,但如果您在自己实施此过程中遇到问题,请留下评论,我将在明天发布一些代码示例。没有上下文,它们不会有太多意义。

这似乎解决了问题!我曾经尝试过这个方法,但当时它没有起作用。可能是因为我还有其他错误,现在它按照预期工作了。 - manabreak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接