Ktor Client 3.0.0中Bearer Token刷新请求遇401时如何避免死锁?
Ktor Client 3.0.0:刷新令牌失败时的死锁防范与处理
默认防死锁逻辑
Ktor的BearerAuth插件内置了防止刷新令牌请求死循环的机制:
- 当首次API请求返回401时,插件会触发一次刷新令牌请求,同时通过原子状态标记当前正在进行刷新操作,避免多个并发请求重复触发刷新流程。
- 如果刷新令牌请求本身返回401(比如刷新令牌过期或无效),插件会立即终止刷新流程,将失败状态同步给所有等待中的请求,不会再次发起刷新请求,直接返回401错误给调用方,从根源上避免死锁或无限循环。
自定义处理刷新失败场景
如果需要在刷新失败时执行自定义逻辑(比如清除本地令牌、触发重新登录),可以在配置BearerAuth时,通过refreshTokens函数捕获刷新失败的情况:
val client = HttpClient(OkHttp) { install(BearerAuth) { loadTokens { // 从本地存储加载当前的访问令牌和刷新令牌 TokenHolder( accessToken = getSavedAccessToken(), refreshToken = getSavedRefreshToken() ) } refreshTokens { oldTokens -> runCatching { // 发起刷新令牌请求 val response = client.post("https://your-auth-server/token/refresh") { contentType(ContentType.Application.FormUrlEncoded) setBody(listOf("grant_type" to "refresh_token", "refresh_token" to oldTokens.refreshToken)) } if (response.status == HttpStatusCode.Unauthorized) { // 刷新令牌无效,清除本地存储的令牌 clearSavedTokens() // 抛出异常终止插件流程 throw RefreshTokenInvalidException() } // 解析新令牌并保存 val newTokens = response.body<TokenResponse>() TokenHolder(newTokens.accessToken, newTokens.refreshToken).also { saveTokens(it) } }.getOrElse { // 处理刷新过程中的异常(网络错误、令牌无效等) clearSavedTokens() throw it } } } } // 自定义异常类,用于标记刷新令牌无效的情况 class RefreshTokenInvalidException : Exception("Refresh token is invalid or expired")
关键注意事项
- 不要在
refreshTokens函数中再次触发需要认证的API请求,否则可能引发意外循环。 - 刷新令牌失败后,建议立即清除本地存储的令牌,避免后续请求继续使用无效令牌触发不必要的刷新流程。
内容的提问来源于stack exchange,提问作者Ali Bagherifam
相关产品推荐
相关产品推荐

