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

请求失败时如何替换/切换API请求URL?

请求失败一次后切换URL重试的实现方案

需求说明

首次请求www.abc.com/whatever失败(HTTP异常、解析异常等)后,后续重试需自动切换到www.abc-2.com/whatever,要求尽量不修改现有safeApiCall工具方法,且不使用Interceptor迁移重试逻辑。

现有代码

1. safeApiCall工具方法

suspend fun <T> safeApiCall(apiCall: suspend () -> Response<T>): Result<T> {
    val maxRetries = 5
    var retryCount = 0 // 原代码val无法修改,修正为var
    while (retryCount < maxRetries) {
        try {
            val response = apiCall.invoke()
            if (response.isSuccessful && response.body() != null) {
                return Result.success(response.body()!!)
            } else {
                retryCount++  
            }
        } catch(e: Exception) {
            // do some logging
            retryCount++  
        }
    }
    return Result.failure(Exception("Max retries exceeded")) // 补充重试耗尽后的返回逻辑
} 

2. Suspend风格API接口

interface MyApiService {
    @GET
    suspend fun getApiData(
        @Url completeUrl: String,
        @QueryMap queries: Map<String, String>,
        @HeaderMap headerMap: Map<String, String> = hashMapOf()
    ): Response<MyApiData>
}

3. 原调用方式

suspend fun getMyApiResponse(): Result<MyApiData> {
    return safeApiCall {
        apiService.getApiData(
            completeUrl = "www.abc.com/whatever",
            queries = emptyMap(),
        )
    }
}

解决方案

利用闭包保存状态,在调用safeApiCall时传入的lambda内部维护URL切换逻辑,无需修改safeApiCall核心逻辑:

suspend fun getMyApiResponse(): Result<MyApiData> {
    // 闭包变量,记录当前重试尝试次数
    var currentAttempt = 0
    return safeApiCall {
        // 根据尝试次数选择目标URL:首次用主地址,后续重试用备用地址
        val targetUrl = if (currentAttempt == 0) {
            "www.abc.com/whatever"
        } else {
            "www.abc-2.com/whatever"
        }
        
        // 执行API请求
        val response = apiService.getApiData(
            completeUrl = targetUrl,
            queries = emptyMap()
        )
        
        // 每次执行请求后尝试次数自增(仅请求失败时,safeApiCall会再次调用该lambda)
        currentAttempt++
        response
    }
}

方案原理

  1. 闭包状态维护:currentAttempt作为闭包变量,会在safeApiCall循环调用lambda时保留其值;
  2. URL自动切换:首次调用lambda时currentAttempt为0,使用主URL;若请求失败,safeApiCall触发重试,此时currentAttempt已自增为1,自动切换到备用URL;
  3. 兼容所有失败场景:无论是HTTP响应失败还是抛出异常,safeApiCall都会触发重试,lambda会自动使用备用URL,符合需求。

扩展优化(支持多备用URL)

如果需要配置多个备用地址,可以将URL列表化,根据尝试次数动态选择:

suspend fun getMyApiResponse(): Result<MyApiData> {
    val urlList = listOf(
        "www.abc.com/whatever",
        "www.abc-2.com/whatever",
        "www.abc-3.com/whatever" // 可扩展更多备用地址
    )
    var currentAttempt = 0
    return safeApiCall {
        // 若尝试次数超过列表长度,复用最后一个备用地址
        val targetUrl = urlList.getOrElse(currentAttempt) { urlList.last() }
        val response = apiService.getApiData(
            completeUrl = targetUrl,
            queries = emptyMap()
        )
        currentAttempt++
        response
    }
}

内容的提问来源于stack exchange,提问作者Anshul Tripathi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 09:08:11