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

异常发生后重新执行代码的最佳方案?Rest API令牌过期场景咨询

别用GoTo!试试这些更优雅的重试方案

首先直接给结论:强烈不建议用GoTo来处理这种重试场景——虽然它能实现功能,但会让代码的控制流变得混乱,后续维护起来简直是噩梦,尤其是团队协作的时候,别人读你的代码得跟着GoTo跳来跳去,很容易出错。

接下来给你几个更合理的方案,从基础到进阶都有:

方案1:手动循环控制重试

把API调用的逻辑封装成循环,用重试次数来控制终止条件,逻辑清晰,线性易读。

举个C#的例子(看你提到try/catch,推测是.NET环境):

public async Task<ApiResponse> CallProtectedApi(string endpoint, int maxRetries = 2)
{
    int retryAttempts = 0;
    
    while (true)
    {
        try
        {
            // 先拿当前的有效令牌
            var currentToken = GetStoredToken();
            // 发起API请求
            var request = new HttpRequestMessage(HttpMethod.Get, endpoint);
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", currentToken);
            
            var response = await _httpClient.SendAsync(request);
            response.EnsureSuccessStatusCode(); // 触发HTTP错误异常,包括令牌过期对应的401
            
            return await response.Content.ReadFromJsonAsync<ApiResponse>();
        }
        catch (HttpRequestException ex) when (IsTokenExpiredException(ex))
        {
            retryAttempts++;
            if (retryAttempts > maxRetries)
            {
                // 重试次数耗尽,抛出异常或返回错误
                throw new InvalidOperationException("Failed to refresh token after multiple attempts.", ex);
            }
            
            // 刷新令牌
            await RefreshAuthToken();
            // 循环继续,自动重试API调用
        }
        catch (Exception ex)
        {
            // 处理其他异常(如网络故障、API内部错误),这里直接抛出
            throw;
        }
    }
}

// 辅助方法:判断是否为令牌过期异常(比如401状态码)
private bool IsTokenExpiredException(HttpRequestException ex)
{
    return ex.StatusCode == HttpStatusCode.Unauthorized;
    // 可进一步检查响应内容的错误信息,确认是令牌过期
}

// 刷新令牌的逻辑
private async Task RefreshAuthToken()
{
    var refreshPayload = new StringContent(
        JsonSerializer.Serialize(new { RefreshToken = _storedRefreshToken }),
        Encoding.UTF8,
        "application/json"
    );
    var refreshResponse = await _httpClient.PostAsync("/api/refresh-token", refreshPayload);
    refreshResponse.EnsureSuccessStatusCode();
    
    var newTokenData = await refreshResponse.Content.ReadFromJsonAsync<TokenResponse>();
    // 更新存储的令牌和刷新令牌
    _storedToken = newTokenData.AccessToken;
    _storedRefreshToken = newTokenData.RefreshToken;
}

这个方案的好处:

  • 控制流清晰,顺着代码就能理解重试逻辑
  • 限制重试次数,避免无限循环(比如刷新令牌也失败的情况)
  • 令牌管理与API调用逻辑解耦,后续修改其中一个不影响另一个

方案2:用成熟的重试库(比如Polly)

如果项目复杂度高,或需要更灵活的重试策略(如重试间隔、熔断、降级),直接用现成库更省心。.NET生态里最常用的就是Polly。

用Polly实现的话,代码会更简洁:

// 定义重试策略:捕获令牌过期异常,最多重试2次,每次重试前刷新令牌
var tokenRefreshRetryPolicy = Policy
    .Handle<HttpRequestException>(ex => IsTokenExpiredException(ex))
    .RetryAsync(2, async (exception, retryCount) =>
    {
        await RefreshAuthToken();
    });

// 执行API调用
var apiResponse = await tokenRefreshRetryPolicy.ExecuteAsync(async () =>
{
    var currentToken = GetStoredToken();
    var request = new HttpRequestMessage(HttpMethod.Get, endpoint);
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", currentToken);
    
    var response = await _httpClient.SendAsync(request);
    response.EnsureSuccessStatusCode();
    
    return await response.Content.ReadFromJsonAsync<ApiResponse>();
});

Polly的优势:

  • 无需手动写循环和计数,代码更简洁
  • 支持高级策略:指数退避(重试间隔逐渐延长)、熔断(连续失败暂停重试)、超时控制等
  • 社区成熟,文档完善,问题排查更方便

为什么GoTo是坏选择?

GoTo会打破代码的线性结构,后续逻辑变复杂后,代码容易变成“面条代码”,别人很难理清执行顺序。现代编程范式更强调结构化控制流,循环、函数调用这些方式比GoTo更符合可读性和可维护性要求。

当然,GoTo不是绝对不能用(比如嵌套循环中跳出多层),但在这种重试场景下,完全有更优雅的替代方案,没必要用GoTo。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:37:48