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

Android Ktor中Token刷新后API重试失败的检测与处理方法

解决Ktor刷新Token后重试请求失败的登出处理问题

要检测刷新Token后的重试请求是否失败,核心思路是给刷新Token后的重试请求打上标记,然后在响应校验器中识别这个标记,一旦标记存在且请求失败,就执行登出操作。Ktor提供的AttributeKey机制可以安全地给请求附加自定义元数据,这是最符合Ktor idiomatic风格的实现方式。

实现步骤

1. 定义自定义属性键

先定义一个全局的AttributeKey,用于标记请求是否是Token刷新后的重试请求:

// 标记该请求是Token刷新后的重试请求
private val RETRIED_AFTER_TOKEN_REFRESH = AttributeKey<Boolean>("RetriedAfterTokenRefresh")

2. 修改Bearer认证配置,给重试请求打标记

在bearer认证的sendAuthenticatedRequest回调中,拦截所有带Bearer Token的请求,当请求是刷新Token后的重试请求时,为其添加标记:

val client = HttpClient {
    install(Auth) {
        bearer {
            // 拦截带Token的请求,给刷新后的重试请求打标记
            sendAuthenticatedRequest { request, tokens ->
                // 仅当Token存在(说明是刷新后重试)且未标记过时,添加标记
                if (tokens != null && !request.attributes.contains(RETRIED_AFTER_TOKEN_REFRESH)) {
                    request.attributes.put(RETRIED_AFTER_TOKEN_REFRESH, true)
                }
                // 继续执行请求流程
                proceed(request, tokens)
            }

            refreshTokens {
                val newToken = refreshAccessToken() // 调用刷新Token的API
                if (newToken != null) {
                    TokenStorage.saveTokens(newToken) // 保存新Token
                    newToken
                } else {
                    // 刷新Token失败直接执行登出
                    logOutUser()
                    null
                }
            }
        }
    }

    // 其他配置...
}

3. 在响应校验器中检测标记并处理登出

在HttpResponseValidator中,检查当前失败请求是否带有重试标记,若存在则执行登出操作:

HttpResponseValidator {
    handleResponseExceptionWithRequest { exception, request ->
        when (exception) {
            is ResponseException -> {
                val statusCode = exception.response.status
                val (value, description) = HttpStatusCode.fromValue(statusCode.value)

                val vivekException = runCatching {
                    Json.decodeFromString<VivekException>(exception.response.bodyAsText())
                }.getOrElse { e ->
                    VivekException(
                        value,
                        description,
                        serverMessage = "Failed to parse server error: ${e.message}"
                    )
                }

                // 检测是否是刷新Token后的重试请求失败
                if (request.attributes.contains(RETRIED_AFTER_TOKEN_REFRESH)) {
                    logOutUser() // 重试仍失败,执行登出
                }

                throw vivekException
            }

            else -> throw VivekException(null, null, serverMessage = exception.message)
        }
    }
}

方案说明

  • 该方案利用Ktor的AttributeKey实现请求级别的元数据跟踪,每个请求的attributes都是独立的,不会有并发问题,完全符合Ktor的设计理念。
  • 仅当刷新Token成功后发起的重试请求失败时,才会触发登出,避免了第一次请求返回401就直接登出的误判。
  • 若刷新Token本身失败,refreshTokens块中已经处理了登出逻辑,覆盖了所有异常场景。

内容的提问来源于stack exchange,提问作者Compose Learner

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 17:26:08