序列化RxSwift

时间:2016-08-15 16:37:24

标签: concurrency rx-swift

我正在使用RxSwift开发自己的OAuth2实现。为了验证请求,我有一个获取和存储访问令牌的Authenticator。因此,如果我有一个有效的访问令牌,Authenticator将立即返回它,否则它将向服务器执行请求。这正是accessTokenRequest()所做的。

request = authenticator
            .accessTokenRequest()
            .map(toAuthorizationHeader)
            .flatMap {self.actualRequest(withEndpoint: endpoint, authHeader: $0)}

问题在于,当我有多个请求身份验证的请求并且没有存储有效的访问令牌时,身份验证器也会发出多个访问令牌请求。这是不可取的,因为理想情况下,只应执行第一个访问令牌请求,并且所有后续请求应等到Authenticator完成获取访问令牌。

基本上我想序列化函数accessTokenRequest(),就像关键区域一样。

关于如何实现这一目标的任何想法?

非常感谢!

更新

这是accessTokenRequest()函数

的简化内容
func accessTokenRequest() -> Observable<OAuth2Credential> {
    if let credential = self.cachedCredential where !credential.isExpired  {

        // All subsequent requests should already enter here and return right away

        return Observable.just(credential)
    }

    ...

    // First request should reach here and request access token from the server.

    return NetworkClient.AccessToken()
            .doOnNext(cacheCredential)
}

1 个答案:

答案 0 :(得分:0)

刚才看到这个问题已经存在了一段时间,所以无论如何我都会为将来真正需要这个问题的人提供答案。

有几种解决方案,让我们看看如何以不同的方式实现这一目标。

不缓存

如果您不需要缓存,可以将accessTokenRequest()转换为共享,并使用shareReplay(1)重播可观察对象。这意味着内部observable将触发单个请求,然后将结果共享给所有订阅或连接的observable,因此更改将是:

func accessTokenRequest() -> Observable<OAuth2Credential> {
    // First request should reach here and request access token from the server.
    return NetworkClient.AccessToken().shareReplay(1)
}

使用缓存

更新的代码看起来很适合缓存解决方案,但是在这里我还会添加一个shareReplay,我不会在每次需要这个observable时看到执行内部任务的要点,所以这边-effect得到共享。当然,如果调用失败的话,这是一个很好的解决方案,如果我还要添加一个retry,以避免在失败后终止可观察的事件。