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

ASP.NET Core Web API第三方API响应超时处理方案咨询

ASP.NET Core Web API 超时返回+后台处理实现方案

核心逻辑

通过Task.WhenAny同时等待第三方API请求和超时延迟任务:

  • 若第三方请求先完成,直接返回结果给用户;
  • 若超时延迟先触发,立即返回错误响应,同时启动后台任务继续等待第三方响应,完成后将结果存储。

代码实现

1. 自定义响应存储服务

先定义一个用于存储第三方响应的服务,这里以内存存储为例(实际可替换为数据库、Redis等持久化存储):

public interface IResponseStorageService
{
    Task StoreResponseAsync(string requestId, string responseContent);
}

public class InMemoryResponseStorageService : IResponseStorageService
{
    private readonly Dictionary<string, string> _storage = new();
    private readonly object _lockObj = new();

    public Task StoreResponseAsync(string requestId, string responseContent)
    {
        lock (_lockObj)
        {
            _storage[requestId] = responseContent;
        }
        return Task.CompletedTask;
    }
}

2. Controller 实现

在ControlDevice接口中实现超时控制和后台处理逻辑,注入IHttpClientFactory和IResponseStorageService:

[ApiController]
[Route("api/[controller]")]
public class ControlDeviceController : ControllerBase
{
    private readonly HttpClient _httpClient;
    private readonly IResponseStorageService _storageService;
    private readonly ILogger<ControlDeviceController> _logger;
    private const int TimeoutSeconds = 3; // 设置3秒超时

    public ControlDeviceController(IHttpClientFactory httpClientFactory, 
                                   IResponseStorageService storageService,
                                   ILogger<ControlDeviceController> logger)
    {
        _httpClient = httpClientFactory.CreateClient("ThirdPartyApi");
        _storageService = storageService;
        _logger = logger;
    }

    [HttpPost]
    public async Task<IActionResult> ControlDevice([FromBody] DeviceControlRequest request)
    {
        var requestId = Guid.NewGuid().ToString(); // 生成唯一请求ID,用于关联后续响应
        var thirdPartyTask = CallThirdPartyApiAsync(request, requestId);
        
        // 等待第三方请求或超时
        var completedTask = await Task.WhenAny(thirdPartyTask, Task.Delay(TimeSpan.FromSeconds(TimeoutSeconds)));

        if (completedTask == thirdPartyTask)
        {
            // 第三方请求在超时前完成,直接返回结果
            var response = await thirdPartyTask;
            return Ok(response);
        }
        else
        {
            // 超时,立即返回错误,后台继续处理
            _ = Task.Run(async () =>
            {
                try
                {
                    var delayedResponse = await thirdPartyTask;
                    await _storageService.StoreResponseAsync(requestId, delayedResponse);
                    _logger.LogInformation("第三方延迟响应已存储,RequestId: {RequestId}", requestId);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "后台处理第三方响应失败,RequestId: {RequestId}", requestId);
                }
            });

            return StatusCode(StatusCodes.Status504GatewayTimeout, new 
            { 
                Message = "请求超时,后台将继续处理设备控制任务",
                RequestId = requestId 
            });
        }
    }

    private async Task<string> CallThirdPartyApiAsync(DeviceControlRequest request, string requestId)
    {
        // 构造第三方API请求,这里示例用PostAsync,实际根据第三方接口调整
        var content = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json");
        var response = await _httpClient.PostAsync("/api/device/control", content);
        
        response.EnsureSuccessStatusCode(); // 若第三方返回错误,抛出异常
        return await response.Content.ReadAsStringAsync();
    }
}

// 设备控制请求模型
public class DeviceControlRequest
{
    public string DeviceId { get; set; }
    public string Command { get; set; }
}

3. 服务注册

在Program.cs中注册所需服务:

var builder = WebApplication.CreateBuilder(args);

// 添加HttpClient,配置第三方API基础地址
builder.Services.AddHttpClient("ThirdPartyApi", client =>
{
    client.BaseAddress = new Uri("https://third-party-api.example.com/");
});

// 注册响应存储服务
builder.Services.AddSingleton<IResponseStorageService, InMemoryResponseStorageService>();

builder.Services.AddControllers();
// ... 其他服务注册

var app = builder.Build();

// ... 中间件配置

app.Run();

关键注意事项

  • 后台任务可靠性:上述示例用Task.Run启动后台任务,若应用进程重启,未完成的任务会丢失。如果需要更高可靠性,建议使用Hangfire、Quartz等任务调度框架,或者将任务提交到消息队列(如RabbitMQ),由独立的后台服务消费处理。
  • 第三方请求取消:示例中未给第三方请求传递取消令牌,确保超时后请求仍能继续执行。若需要根据业务场景取消请求,可调整CallThirdPartyApiAsync方法传入CancellationToken,但要注意这会终止第三方请求,无法获取后续响应。
  • 异常处理:后台任务必须捕获所有异常,避免未处理异常导致进程崩溃,同时通过日志记录错误信息便于排查。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 21:33:28