【问题标题】:RxJava - return after some method is completedRxJava - 在某个方法完成后返回
【发布时间】:2018-04-09 20:54:45
【问题描述】:

我对 RxJava 很陌生,我正在尝试在我的 Android/Kotlin 应用程序中使用刷新令牌实现 OAuth2 流。

在拦截器中刷新访问令牌时我有点卡住了(我在 OAuthAuthenticator 中为每个 API 请求附加访问令牌)。问题是我想等到令牌请求完成后再填充请求。

有人可以提示我如何做到这一点吗?

这是我的验证器类:

class OAuthAuthenticator(
        private val authStateManager: AuthStateManager,
        private val authRepository: AuthRepository): Authenticator {

    override fun authenticate(route: Route?, response: Response?): Request? {

        // handle invalid token
        if (response != null && response.code() == 401) {
            println("Invalid access token")

            authRepository.refreshToken()
                    .subscribe { _ ->
                        println("Token refreshed")
                    }
        }

        // this should happen after the token request is completed since it would fail again otherwise
        return response?.request()!!
                .newBuilder()
                .header("Authorization", "Bearer " + authStateManager.current.accessToken)
                .build()
    }
}

【问题讨论】:

    标签: android kotlin rx-java2


    【解决方案1】:

    您正在同步方法中进行异步调用。那是行不通的。在令牌请求完成后,您必须将要执行的代码放入 rx 链中。

    class OAuthAuthenticator(
            private val authStateManager: AuthStateManager,
            private val authRepository: AuthRepository) : Authenticator {
    
            override fun authenticate(route: Route?, response: Response?): Single<Request> {
                // handle invalid token
                if (response != null && response.code() == 401) {
                    return Single.error(InvalidAccessTokenException("Invalid access token"))
                }
    
                return Single.fromCallable { authRepository.refreshAccessToken() }
                    .subscribeOn(Schedulers.computation())
                    .map {
                        return@map response?.request()!!
                            .newBuilder()
                            .header("Authorization", "Bearer " +
                                    authStateManager.current.accessToken)
                            .build()
                    }
            }
        }
    

    然后你可以这样称呼它:

    val authenticator = OAuthAuthenticator(authStateManager, authRepository)
    val disposable = authenticator.authenticate(route, response)
                .subscribe({ _ ->
                    println("Token refreshed")
                }, { error ->
                    if (error is InvalidAccessTokenException) {
                        println("Invalid access token")
                    } else {
                        println("Could not refresh token. Signing out...")
                        authStateManager.signOut()
                    }
                })
    

    【讨论】:

    • 感谢您的回答。不幸的是,OkHttp 身份验证器的 itnerface 规定此方法必须返回 Result,而不是 Single&lt;Result&gt;,因此这不起作用。该认证器注册在 OkHttp3 客户端,内部使用。
    • 哦,我明白了。在这种情况下,您甚至可能不需要在 authenticate 方法中使用 rxjava,因为它应该在默认情况下在后台线程上执行。
    • 但是如果完成,我如何让它等到令牌请求?如果我不以某种方式使其同步,身份验证器将尝试使用旧令牌在行中执行多个请求..
    • authRepository.refreshAccessToken() 返回什么?
    • 它不返回任何东西。它执行一些请求(我们正在使用 AppAuth 框架)并在完成后更新其身份验证状态
    【解决方案2】:

    您可以使用blockingGet() 使Single 同步。但不建议这样做。但是由于您使用

    在本地创建Single
    Single.fromCallable { authRepository.refreshAccessToken() }
    

    你可以直接调用适当的方法而不用 Rx 包装它。

    if (response != null && response.code() == 401) {
        println("Invalid access token")
        try {
            authRepository.refreshAccessToken()
            println("Token refreshed")
        } catch(error: Throwable) {
            println("Could not refresh token. Signing out...")
            authStateManager.signOut()
            return null
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-19
      • 1970-01-01
      • 2022-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多