异常发生后重新执行代码的最佳方案?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
相关产品推荐
相关产品推荐

