如何实现不依赖内部方法的KTor客户端外部条件触发重试机制?
不依赖KTor内部API的自定义重试实现方案
核心思路
用KTor公开的HttpSend拦截器实现自定义重试逻辑,完全避开内部方法,同时支持等待外部用户操作(比如重新授权)后再重试。
具体实现步骤
- 拦截响应并判断重试条件:通过
HttpSend拦截器捕获请求响应,根据状态码(比如401 Unauthorized)触发重试逻辑。 - 挂起等待外部操作完成:用协程的
CompletableDeferred实现等待逻辑,直到用户完成重新授权等外部操作。 - 重新发起原请求:外部条件满足后,直接复用原请求参数重新发起请求。
代码示例
// 用于协调授权等待的工具类,可根据业务场景调整为局部或全局 object AuthCoordinator { private var authDeferred: CompletableDeferred<Unit>? = null // 挂起协程,等待用户完成重新授权 suspend fun awaitReauth() { authDeferred = CompletableDeferred() authDeferred?.await() } // 用户完成授权后调用,唤醒等待的请求协程 fun notifyAuthCompleted() { authDeferred?.complete(Unit) authDeferred = null } } // 配置KTor客户端 val ktorClient = HttpClient(OkHttp) { // 安装自定义重试拦截器 install(HttpSend) { intercept { originalRequest -> var response = execute(originalRequest) // 这里以401为例,可扩展为其他需要重试的状态码 while (response.status == HttpStatusCode.Unauthorized) { // 等待用户完成重新授权 AuthCoordinator.awaitReauth() // 重新发起原请求,复用所有请求参数 response = execute(originalRequest) } response } } // 常规Auth插件配置,按需调整 install(Auth) { bearer { loadTokens { // 加载当前有效token的逻辑 } } } }
关键说明
- 完全基于公开API:整个实现只用到KTor官方文档中公开的
HttpSend拦截器和协程API,没有依赖任何内部方法。 - 灵活扩展:可以轻松添加重试次数限制、不同状态码的分支处理、日志输出等逻辑。
- 协程安全:
AuthCoordinator中的CompletableDeferred每次等待都会重新创建,避免复用导致的逻辑混乱,同时在授权完成后及时清理。 - 请求上下文复用:直接复用
originalRequest确保重试时不会丢失原请求的headers、参数、body等信息。
内容的提问来源于stack exchange,提问作者Austin Brooks
相关产品推荐
相关产品推荐

