【问题标题】:How to retry rxjava request with refresh token in request body?如何在请求正文中使用刷新令牌重试 rxjava 请求?
【发布时间】:2021-09-02 03:13:39
【问题描述】:

该项目使用 OAuth2 协议。但是请求正文中有令牌,而不是标题。所以我找不到用新令牌再次发送请求的方法。 流程:请求 -> 失败 -> 刷新令牌 -> 请求

请求经验:
{“请求”:“asd”, “令牌”:“...”, “请求数据”:{} } 发生错误时,我正在使用相同的令牌发送相同的请求,如下所示:

requestExp().flatMap(resource -> {
          return Single.just(new Object());
    }).retryWhen(th-> {
        AtomicInteger counter = new AtomicInteger();
        return th.takeWhile(e -> {
            if (Objects.equals(e.getMessage(), "test")) {
                return counter.getAndIncrement() != 1;
            } 
        });
    });

有什么帮助吗?

【问题讨论】:

  • 你在使用retrofit/okhttp吗?如果是,您可以为客户端设置身份验证器。当您收到错误 401 时,将调用身份验证器。在身份验证器中,您可以获得新令牌,然后将其添加到您的响应正文中。
  • @DominikSetniewski 身份验证器可以将令牌添加到请求正文吗?你能展示样品吗?感谢您的提前
  • 我相信这是可能的,但看起来很糟糕。:/

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


【解决方案1】:

你可以试试这样的:

    .retryWhen {
            return@retryWhen it.flatMapSingle { throwable ->
                if (throwable is HttpException && throwable.code() == 401) {
                    // when 401 error, let's update the token and retry after that
                    println("Invalid token")
                    return@flatMapSingle refreshToken() // token source will be updated
                }
                // other error, no retry
                return@flatMapSingle Single.error<Any>(throwable)
            }
        }

例子:

fun main() {
    class Params(val token: String)
    class Result

    val tokenSource = BehaviorSubject.create<String>()
    tokenSource.onNext("invalid_token")

    fun request(params: Params): Single<Result> {
        if (params.token != "valid_token") {
            val responseBody = "".toResponseBody("application/json".toMediaTypeOrNull())
            val response = retrofit2.Response.error<Any>(401, responseBody)
            return Single.error(HttpException(response))
        }
        return Single.just(Result())
    }

    fun refreshToken(): Single<String> {
        return Single.fromCallable {
            val token = "valid_token"
            tokenSource.onNext(token)
            return@fromCallable token
        }
    }  

    val s = tokenSource.firstOrError() // get latest token
            .flatMap { request(Params(it)) }
            .retryWhen {
                return@retryWhen it.flatMapSingle { throwable ->
                    if (throwable is HttpException && throwable.code() == 401) {
                        println("Invalid token")
                        return@flatMapSingle refreshToken() // token source will be updated
                    }
                    return@flatMapSingle Single.error<Any>(throwable)
                }
            }
            .subscribe(
                    {
                        println("Success")
                    },
                    {
                        println("Error $it")
                    }
            )

}

【讨论】:

  • “Retrywhen”虽然刷新令牌但发送具有相同值的请求:(我试过这个
  • Retry 重新订阅上游 observable。如果您使用示例中的处理器,您将获得最新值。如果你使用了一个 observable,它在 Rx 组装时间包装了令牌,你会得到旧值。 onErrorResumeNext 也有不同的方法。您可以简单地将刷新令牌 observable 与您的原始 API 请求 observable 链接在一起
猜你喜欢
  • 2020-06-02
  • 1970-01-01
  • 1970-01-01
  • 2019-11-08
  • 2021-11-26
  • 2017-06-09
  • 2022-06-11
  • 2016-01-05
  • 2020-07-12
相关资源
最近更新 更多