You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在retryWhen中刷新Observable参数,实现自动登录后更新原参数

使用retryWhen实现带参数更新的自动登录功能

我最近在做RxJava相关的功能,想要用retryWhen实现一个自动登录的逻辑——就是当接口返回401未授权时,自动调用登录接口,登录成功后更新原请求的参数(比如带上新拿到的token),再重新发起原来的请求。我先写了个TestClass的框架代码,大概是这样:

class TestClass(): Function<Flowable<out Throwable>, Flowable<*>> {
    override fun apply(flowable: Flowable<out Throwable>): Flowable<*> {
        return flowable
            .flatMap {
                if (it is HttpException && it.code() == 401 ) {
                    Timber.d("apply: Doing AutoLogin.")
                    dataSource.login(document, password)
                    // 这里需要处理登录成功后更新原请求参数的逻辑
                } else {
                    // 非401错误直接抛出,不重试
                    Flowable.error(it)
                }
            }
    }
}

这里的核心难点是:retryWhen默认只能触发重试,但没法直接修改原Observable的请求参数。我摸索出了一套可行的实现方案,分享给大家:

实现思路

  1. 把原请求的动态参数(比如token)封装成线程安全的可变容器,这样登录成功后可以直接更新容器内的值;
  2. 在retryWhen的逻辑里,完成自动登录后更新参数容器,再返回触发重试的信号;
  3. 原请求的Observable每次都从参数容器中读取最新值,确保重试时用的是更新后的参数。

完整代码示例

// 定义线程安全的参数容器,存储需要动态更新的请求参数
class RequestParamsHolder {
    // 用AtomicReference保证多线程环境下的参数读写安全
    val token = AtomicReference<String?>()
    // 可扩展其他需要动态更新的参数,比如登录凭证、请求签名等
}

// 改造后的自动登录重试处理器
class AutoLoginRetryHandler(
    private val dataSource: LoginDataSource,
    private val paramsHolder: RequestParamsHolder,
    // 提供获取最新登录凭证的方法(比如从本地缓存读取)
    private val getLoginCredentials: () -> Pair<String, String>
) : Function<Flowable<out Throwable>, Flowable<*>> {

    override fun apply(errors: Flowable<out Throwable>): Flowable<*> {
        return errors.flatMap { throwable ->
            when {
                // 仅处理401未授权错误
                throwable is HttpException && throwable.code() == 401 -> {
                    Timber.d("触发自动登录流程")
                    val (document, password) = getLoginCredentials()
                    // 执行自动登录请求
                    dataSource.login(document, password)
                        .doOnSuccess { loginResult ->
                            // 登录成功后更新参数容器中的token
                            paramsHolder.token.set(loginResult.token)
                            Timber.d("自动登录成功,已更新请求token")
                        }
                        // 登录成功后返回信号,触发原请求重试
                        .map { Unit }
                        // 登录失败则直接抛出错误,终止重试流程
                        .onErrorReturn { Flowable.error(it) }
                }
                // 非401错误直接抛出,不进行重试
                else -> Flowable.error(throwable)
            }
        }
    }
}

// 使用示例:发起需要自动登录重试的请求
fun makeAuthorizedRequest(paramsHolder: RequestParamsHolder): Flowable<ApiResponse> {
    return apiService.fetchData(
        // 每次请求都从参数容器中读取最新的token
        token = paramsHolder.token.get() ?: ""
    )
        .retryWhen(AutoLoginRetryHandler(dataSource, paramsHolder) {
            // 这里从本地缓存(比如SharedPreferences)获取登录凭证
            Pair("user_document", "user_password")
        })
}

关键细节说明

  • 参数容器的线程安全:用AtomicReference是因为RxJava的操作可能在不同线程执行,它能避免参数读写时的线程安全问题;
  • 重试触发逻辑:登录成功后返回的Unit信号会通知retryWhen重新订阅原Observable,而原请求会自动读取参数容器里的最新值,实现带新参数的重试;
  • 避免无限循环:如果自动登录失败(比如密码过期、账号锁定),直接抛出错误终止重试,不会陷入死循环。

内容的提问来源于stack exchange,提问作者Gibran Lyra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:54:23