使用OkHttp认证时Authenticator如何等待刷新token结果后返回Request
关于OkHttp Authenticator中同步等待刷新Token结果的解决方案
核心原理
Authenticator的authenticate方法本身由OkHttp在独立的后台工作线程调用,并非UI线程,因此你可以在该方法内执行同步阻塞操作等待Token刷新结果,不会导致界面卡顿。
不同实现方案的正确写法
1. RXJava 版本
你之前的写法问题在于doOnSuccess是异步回调,回调执行时外层authenticate方法已经结束返回,无法将结果返回给外层。直接使用RX提供的同步阻塞方法blockingGet()即可拿到结果:
class TokenAuthenticator : Authenticator { override fun authenticate(route: Route?, response: Response): Request? { return try { // 同步阻塞等待刷新Token接口返回 val newToken = getTokenFromServer()?.blockingGet()?.result?.token ?: return null // 构造携带新Token的请求返回 response.request.newBuilder() .addHeader("token", newToken) .build() } catch (e: Exception) { // 刷新失败,返回null让OkHttp放弃重试 null } } fun getTokenFromServer(): Single<ApiResponse>? { // 原有刷新Token的接口实现 } }
2. 协程版本
你第二种协程写法的思路是对的,runBlocking会阻塞当前线程直到内部协程执行完成,刚好符合我们需要同步返回结果的要求:
class TokenAuthenticator : Authenticator { override fun authenticate(route: Route?, response: Response): Request? { return runBlocking(Dispatchers.IO) { try { val newToken = getTokenFromServer()?.result?.token ?: return@runBlocking null response.request.newBuilder() .addHeader("token", newToken) .build() } catch (e: Exception) { null } } } // 注意这里getTokenFromServer要改成suspend挂起函数的实现 suspend fun getTokenFromServer(): ApiResponse? { // 协程版本的刷新Token接口实现 } }
你的疑问解答
- 关于RX无法在
doOnSuccess返回Request:doOnSuccess是异步回调,执行时机晚于authenticate方法返回的时机,自然无法向外层方法返回结果,同步取结果必须用blockingGet。 - 关于第一种协程写法报错:
join是suspend方法,只能在协程作用域内调用,你不需要额外launch再join,直接在runBlocking内部执行挂起函数拿结果即可,也就是第二种写法的逻辑。 - 关于
runBlocking是否会阻塞UI线程:完全不会,OkHttp的authenticate回调本身运行在OkHttp自建的后台线程池,runBlocking阻塞的只是当前这个后台工作线程,和UI线程完全隔离,不会导致应用卡死。
额外注意事项
- 要添加失败处理逻辑,刷新Token失败时直接返回null,避免OkHttp无限重试。
- 建议加互斥锁(比如使用Mutex),避免多个请求同时触发401时,重复调用刷新Token接口导致refresh token失效。
内容的提问来源于stack exchange,提问作者Shahryar Khosravi
相关产品推荐
相关产品推荐

