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

Polly中结合瞬时故障捕获与重新授权的实现问题

解决Polly重试+401自动重认证的问题

我懂你这个痛点!Polly的策略组合确实容易在顺序和细节上踩坑,你的代码里有几个核心问题导致401重新认证后原请求没重试,咱们一步步来改:

问题分析

  1. 策略包裹顺序搞反了
    你当前用WaitAndRetryPolicy.WrapAsync(ReAuthPolicy),意味着Polly会先执行重认证策略,再执行网络重试策略。但我们需要的逻辑是:先发起请求(带网络重试),如果返回401,再触发重认证,然后重新执行整个请求流程(包括网络重试)。顺序反了就会导致重认证后不会再走原请求的重试逻辑。

  2. 重认证后没更新请求的Token
    你的LogInWithSavedCredsAsync虽然执行成功,但如果没把新获取的JWT更新到_client的请求头里,下次请求还是用旧的过期Token,自然还是401,等于白重认证了。

  3. 没处理重认证失败的场景
    当前策略没考虑“重认证也返回401”的情况,这时候应该直接终止流程并登出用户,而不是继续重试。

修正后的完整代码

// 核心:调整策略包裹顺序,重认证策略在外层,包裹网络重试策略
public static PolicyWrap<HttpResponseMessage> RetryPolicy {
    get => ReAuthPolicy.WrapAsync(WaitAndRetryPolicy);
}

// 网络故障重试策略:只处理网络异常和非401的错误响应
private static IAsyncPolicy<HttpResponseMessage> WaitAndRetryPolicy {
    get => Policy
        .Handle<WebException>()
        .Or<HttpRequestException>()
        .OrResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode && r.StatusCode != HttpStatusCode.Unauthorized)
        .WaitAndRetryAsync(4, _ => TimeSpan.FromSeconds(2), 
            (exception, timespan, retryCount, context) =>
            {
                // 可选:添加重试日志
                Console.WriteLine($"网络请求失败,第{retryCount}次重试,间隔{timespan.TotalSeconds}秒");
            });
}

// 401重认证策略:处理未授权响应,重认证后更新Token,失败则登出
private static IAsyncPolicy<HttpResponseMessage> ReAuthPolicy {
    get => Policy
        .HandleResult<HttpResponseMessage>(x => x.StatusCode == HttpStatusCode.Unauthorized)
        .RetryAsync(1, async (responseDetails, retryCount, context) =>
        {
            // 执行自动重认证
            bool authSuccess = await App.CoreService.LogInWithSavedCredsAsync(true);
            
            if (!authSuccess)
            {
                // 重认证失败:登出用户并终止流程
                await App.CoreService.LogOutAsync();
                throw new UnauthorizedAccessException("保存的凭据已失效,已自动登出");
            }

            // 关键步骤:更新HttpClient的Authorization头为新Token
            string newToken = App.CoreService.GetCurrentValidToken(); // 假设你有这个方法获取最新Token
            _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", newToken);
        });
}

代码说明

  • 策略顺序修正:现在ReAuthPolicy作为外层,当内层的WaitAndRetryPolicy执行完(包括4次网络重试)后,如果返回401,外层会触发重认证,然后重新执行整个内层流程(也就是重新发起原请求+网络重试)。
  • 排除401的网络重试:让网络重试策略只处理真正的网络故障,把401的逻辑完全交给重认证策略,避免冲突。
  • 更新请求Token:重认证成功后必须更新HttpClient的请求头,确保后续请求用的是有效Token。
  • 处理重认证失败:如果保存的凭据也失效了,直接登出用户并抛出异常,终止Polly流程,不会无意义地重试。

使用示例

try
{
    HttpResponseMessage result = await RetryPolicy.ExecuteAsync(() => _client.SendAsync(request));
    // 处理成功响应
    result.EnsureSuccessStatusCode(); // 可选:把非成功响应转为异常
}
catch (UnauthorizedAccessException ex)
{
    // 处理登出后的逻辑,比如跳转到登录页面
}
catch (Exception ex)
{
    // 处理网络重试4次后仍然失败的情况
}

最后别忘了确保LogInWithSavedCredsAsync能正确返回认证结果,GetCurrentValidToken能拿到最新的JWT哦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:25:18