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

ASP.NET Core中如何用Polly根据响应体内容实现自定义重试策略?

构造适配统一返回体的Polly重试策略实现

核心实现思路:由于对接的外部API所有请求均返回200状态码,因此需要自定义策略触发条件,直接解析响应内容判断是否需要重试,同时要处理响应流可重复读取的问题,避免影响后续Refit的反序列化逻辑。

第一步:定义全局可重试错误配置(适配多API通用场景)

可预先定义静态类统一维护可重试的错误标识,比如限流、服务暂时不可用这类允许重试的错误Code,后续多API对接时可直接复用:

public static class RetryableErrorCodes
{
    // 可根据对接API的实际错误码规则补充
    public static readonly HashSet<string> Codes = new()
    {
        "RATE_LIMIT_EXCEEDED", // 限流
        "SERVICE_BUSY", // 服务繁忙
        "GATEWAY_TIMEOUT" // 网关超时
    };
}

第二步:构造重试策略

直接构造IAsyncPolicy<HttpResponseMessage>类型的策略,适配AddPolicyHandler的入参要求:

var retryPolicy = Policy
    .HandleResult<HttpResponseMessage>(async response =>
    {
        // 先把响应内容加载到缓冲区,允许多次读取,避免后续Refit反序列化失败
        await response.Content.LoadIntoBufferAsync();
        
        // 读取响应内容反序列化为统一返回体
        var result = await response.Content.ReadFromJsonAsync<ApiResultResponse>();
        if (result == null) return false;
        
        // 触发重试的条件:Success为false 且 错误列表中存在可重试的错误
        return !result.Success && result.Errors != null 
                               && result.Errors.Any(e => RetryableErrorCodes.Codes.Contains(e.Code));
    })
    .WaitAndRetryAsync(
        retryCount: 3, // 最大重试次数可按需调整
        sleepDurationProvider: (retryAttempt, _) => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), // 指数退避间隔:1s、2s、4s
        onRetryAsync: async (result, timeSpan, retryAttempt, _) =>
        {
            // 重试前的统一日志逻辑,可按需注入ILogger实现
            var apiResult = await result.Result.Content.ReadFromJsonAsync<ApiResultResponse>();
            Console.WriteLine($"请求{apiResult?.RequestId}失败,第{retryAttempt}次重试,错误信息:{string.Join(",", apiResult?.Errors?.Select(e=>e.Message) ?? Array.Empty<string>())}");
        });

若所有Success=false的情况都需要重试,不需要区分错误码,可直接删除错误码判断逻辑,返回!result.Success即可。

第三步:注册到Refit客户端

和原有注册逻辑完全兼容,直接传入构造好的策略即可:

services.AddRefitClient<ISomeApi>(refitSettings)
    .ConfigureHttpClient(c => {
        c.BaseAddress = someApiBaseUrl;
    })
    .AddPolicyHandler(retryPolicy);

多API通用封装方案

如果有多个对接的外部API都使用这套统一返回体,可把策略构造逻辑封装为扩展方法,避免重复代码:

public static class PollyPolicyExtensions
{
    public static IAsyncPolicy<HttpResponseMessage> CreateApiRetryPolicy(int retryCount = 3)
    {
        return Policy
            .HandleResult<HttpResponseMessage>(async response =>
            {
                await response.Content.LoadIntoBufferAsync();
                var result = await response.Content.ReadFromJsonAsync<ApiResultResponse>();
                return result != null && !result.Success && result.Errors != null 
                       && result.Errors.Any(e => RetryableErrorCodes.Codes.Contains(e.Code));
            })
            .WaitAndRetryAsync(
                retryCount: retryCount,
                sleepDurationProvider: (attempt, _) => TimeSpan.FromSeconds(Math.Pow(2, attempt))
            );
    }
}

注册时直接调用扩展方法即可,支持自定义重试次数:

// 对接API1
services.AddRefitClient<ISomeApi>(refitSettings)
    .ConfigureHttpClient(c => c.BaseAddress = someApiBaseUrl)
    .AddPolicyHandler(PollyPolicyExtensions.CreateApiRetryPolicy());

// 对接API2,复用同一套策略
services.AddRefitClient<IOtherApi>(refitSettings)
    .ConfigureHttpClient(c => c.BaseAddress = otherApiBaseUrl)
    .AddPolicyHandler(PollyPolicyExtensions.CreateApiRetryPolicy(5));

注意事项

  • 确保ApiResultResponse和Error类的序列化属性和外部API返回的字段名完全匹配,避免反序列化失败
  • 仅对GET、PUT等幂等请求加重试策略,如果是POST这类非幂等接口,要确认重复提交不会造成业务异常,避免重复下单、重复扣款等问题
  • 若响应体体积很大,LoadIntoBufferAsync会占用较多内存,可根据业务场景调整为流式读取指定字段后重置流位置

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 01:18:04