我有一个使用 OAuth2 进行身份验证并使用 Retrofit 从 RESTful 服务获取数据的应用程序。现在,我已启动并运行 token 检索和刷新。 token 像这样刷新(省略调度程序):
// 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(...);
}
这行得通,但在某些情况下,会同时发送多个请求,并且它们都会调用刷新过程 - 基本上,我的应用最终会刷新 token 的次数与当前请求的次数一样多。
因此,问题是:如何确保在需要刷新 token 时,无论有多少正在进行的请求需要刷新 token ,都只执行一次?我能否以某种方式让其他请求“等待”,直到第一个请求成功调用并检索到新 token ?
最佳答案
我们已经通过使用热可观察对象来刷新 token 并为所有未能通过身份验证的请求提供对其实例的访问来完成此行为。
使用 share
运算符将用于刷新 token 的基本冷可观察对象转变为热可观察对象,以便所有其他订阅者共享其结果。一旦请求返回,所有等待的观察者都会收到通知,在那一刻(在运算符(operator)链中,它恰好在 share()
之前进入 doOnUnsubscribe
的回调)破坏刷新可观察的实例,以便下一个订阅者将创建一个新的。所有这些都可以通过单例模式轻松实现,您可以将刷新的可观察对象包装到单例包装类中,然后通过 getInstance() 请求它。如果没有正在进行的请求——实例为空——getInstance 应该创建一个新的。
您还需要注意一些其他事项,例如刷新期间的错误和使 token 全部无效,但这些是基础知识。
我现在没有太多时间详细说明这一点,但如果您自己实现时遇到问题,请发表评论,我会在明天发布一些代码示例。如果没有上下文,它们就没有多大意义。
关于android - RxJava : How to refresh a token when multiple requests are sent at the same time?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41830515/