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

如何返回408请求超时给Polly以触发其重试策略?

解决方案

问题根源

服务器宕机时,客户端无法收到408响应,而是触发HttpClient超时抛出TaskCanceledException,而Polly的HandleTransientHttpError()默认不处理这类异常,导致重试策略不生效。另外,直接设置HttpClient.Timeout是全局超时(覆盖所有重试请求的总时长),并非单次请求超时,因此无法达到预期效果。

方法一:扩展Polly策略,直接处理超时异常

修改重试策略,添加对超时导致的TaskCanceledException的捕获,排除用户主动取消的情况:

private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        // 仅处理超时引发的取消异常,排除主动取消操作
        .Or<TaskCanceledException>(ex => !ex.CancellationToken.IsCancellationRequested)
        .WaitAndRetryAsync(
            retryCount: 3,
            sleepDurationProvider: currNthRetry => TimeSpan.FromSeconds(Math.Pow(2, currNthRetry)),
            onRetry: (outcome, retryCount, context) =>
            {
                // 可在此添加日志记录,比如输出重试次数、异常信息
            });
}

方法二:用Polly超时策略转化为408响应

使用Polly的TimeoutPolicy控制单次请求超时,并将超时转化为408状态码,让HandleTransientHttpError()自动识别触发重试:

services
    .AddHttpClient<IOrderService, OrderService>(c =>
    {
        c.BaseAddress = new Uri(Configuration["ApiSettings:xxx"]);
        // 将HttpClient全局超时设为更长时间,交由Polly控制单次请求超时
        c.Timeout = TimeSpan.FromMinutes(1);
    })
    .AddPolicyHandler(GetCombinedPolicy());

private static IAsyncPolicy<HttpResponseMessage> GetCombinedPolicy()
{
    // 单次请求超时策略,超时后返回408响应
    var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(5), 
        (context, timespan, task) =>
        {
            return Task.FromResult(new HttpResponseMessage(HttpStatusCode.RequestTimeout));
        });

    var retryPolicy = HttpPolicyExtensions
        .HandleTransientHttpError()
        .WaitAndRetryAsync(
            retryCount: 3,
            sleepDurationProvider: currNthRetry => TimeSpan.FromSeconds(Math.Pow(2, currNthRetry)),
            onRetry: (outcome, retryCount, context) =>
            {
                // 日志记录逻辑
            });

    // 组合策略:先执行单次超时控制,再执行重试
    return Policy.WrapAsync(retryPolicy, timeoutPolicy);
}

关键说明

  • HandleTransientHttpError()默认处理的范围包括:5xx状态码、408请求超时、HttpRequestException(如连接失败、DNS解析错误),但不包含TaskCanceledException。
  • 直接设置HttpClient.Timeout是所有重试请求的总超时,而非单次请求超时,因此无法触发单次超时后的重试。使用Polly超时策略可以精准控制单次请求的超时时间,并将超时转化为标准408响应,适配现有重试逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 17:55:03