Retrofit:如何在OkHttp拦截器中实现请求多次重试功能?
可以在OkHttp拦截器中实现请求重试需求,你遇到的报错是拦截器注册类型错误导致的。
报错根因
你当前将自定义拦截器注册为了OkHttp 网络拦截器,OkHttp官方对网络拦截器有强制限制:每个拦截器的intercept方法必须且仅能调用一次chain.proceed(),你在异常响应分支的循环中多次调用了该方法,因此触发IllegalStateException。
实现方案
方案1:改用应用拦截器(推荐)
OkHttp 应用拦截器没有proceed()仅能调用一次的限制,天然支持重试逻辑,只需将原本注册时调用的addNetworkInterceptor(NetworkErrorHandler())改为addInterceptor(NetworkErrorHandler())即可。
同时建议对原有代码做如下优化,避免内存泄漏和逻辑缺陷:
class NetworkErrorHandler constructor(): Interceptor { // 可自定义最大重试次数 private val maxRetryTimes = 3 override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() var currentRetry = 0 var lastResponse: Response? = null var lastException: Exception? = null while (currentRetry < maxRetryTimes) { try { val response = chain.proceed(request) // 状态码符合预期直接返回 if (response.code == 200 || response.code == 401) { lastResponse?.close() return response } // 异常响应先关闭再重试 response.close() lastResponse = response } catch (e: Exception) { lastException = e } currentRetry++ } // 重试全部失败时优先返回最后一次响应,无响应则抛出异常 return lastResponse ?: throw lastException ?: IllegalStateException("All $maxRetryTimes retry attempts failed") } }
注意:非幂等请求(如POST提交数据、PUT修改资源类接口)不要盲目开启重试,避免出现重复提交数据的业务异常。
方案2:网络拦截器适配方案
如果业务要求必须使用网络拦截器实现重试,不能直接复用原有chain对象多次调用proceed(),每次重试前需通过chain.withReadTimeout()、chain.withWriteTimeout()等方法生成新的Chain实例,用新实例调用proceed()即可符合网络拦截器的限制。
可选优化项
- 增加重试退避策略:每次重试间隔逐步递增(如首次间隔1s、第二次2s、第三次3s),避免瞬时大量重试请求压垮服务端
- 限制可重试的场景:仅网络异常、5xx服务端错误等明确可重试的场景触发重试,400、403等客户端参数/权限错误无需重试
- 可配置不同接口的重试开关:避免全局所有接口都开启重试影响业务稳定性
内容的提问来源于stack exchange,提问作者Ahmad Shahwaiz
相关产品推荐
相关产品推荐

