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

.NET Core 6 API如何取消超时请求并返回504状态码?

在.NET Core 6 API中实现AD查询超时取消并返回504状态码

因为IIS进程内托管模式下,web.config的requestTimeout和IIS原生超时设置不会生效,必须通过.NET Core自身的请求管道和任务取消机制来实现需求,以下是具体实现方案:

一、针对单个接口的超时控制(推荐)

1. 修改服务层方法,支持CancellationToken

确保服务层的AD查询异步方法接受CancellationToken参数,让超时信号能传递到AD查询逻辑中:

public async Task<AdUser> GetAdUserAsync(string userId, CancellationToken cancellationToken)
{
    using var context = new PrincipalContext(ContextType.Domain);
    // 将CancellationToken传入支持异步取消的AD方法(如果方法支持的话)
    var user = await UserPrincipal.FindByIdentityAsync(context, userId);
    
    // 若AD方法不直接支持CancellationToken,用Task.WhenAny包装实现超时
    // var adTask = UserPrincipal.FindByIdentityAsync(context, userId);
    // var timeoutTask = Task.Delay(Timeout.Infinite, cancellationToken);
    // var completedTask = await Task.WhenAny(adTask, timeoutTask);
    // if (completedTask == timeoutTask) throw new OperationCanceledException("AD查询超时");
    // var user = adTask.Result;

    if (user == null)
        throw new KeyNotFoundException("目标AD用户不存在");
    
    return new AdUser 
    { 
        Id = user.SamAccountName, 
        Name = user.DisplayName 
    };
}

2. 控制器中设置超时并处理取消逻辑

在API接口里创建带指定超时时间的CancellationTokenSource,调用服务方法时传入令牌,捕获超时异常后返回504状态码:

[ApiController]
[Route("api/ad")]
public class AdController : ControllerBase
{
    private readonly IAdService _adService;
    private readonly ILogger<AdController> _logger;

    public AdController(IAdService adService, ILogger<AdController> logger)
    {
        _adService = adService;
        _logger = logger;
    }

    [HttpGet("user/{userId}")]
    public async Task<IActionResult> GetAdUser(string userId)
    {
        // 设置超时时间为x分钟,这里示例为5分钟
        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));
        
        try
        {
            var adUser = await _adService.GetAdUserAsync(userId, cts.Token);
            return Ok(adUser);
        }
        catch (OperationCanceledException)
        {
            _logger.LogWarning("AD查询超时,用户ID:{UserId}", userId);
            return StatusCode(StatusCodes.Status504GatewayTimeout, "AD查询超时,请稍后重试");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "AD查询失败,用户ID:{UserId}", userId);
            return StatusCode(StatusCodes.Status500InternalServerError, "查询出错");
        }
    }
}

二、全局请求超时配置(可选)

如果需要给所有API接口统一设置超时规则,可以通过自定义中间件实现:

1. 编写超时中间件

public class RequestTimeoutMiddleware
{
    private readonly RequestDelegate _next;
    private readonly TimeSpan _globalTimeout;

    public RequestTimeoutMiddleware(RequestDelegate next, IConfiguration config)
    {
        _next = next;
        // 从appsettings.json读取全局超时时间(示例:"RequestTimeoutMinutes": 5)
        _globalTimeout = TimeSpan.FromMinutes(config.GetValue<int>("RequestTimeoutMinutes"));
    }

    public async Task InvokeAsync(HttpContext context)
    {
        using var cts = CancellationTokenSource.CreateLinkedTokenSource(context.RequestAborted);
        cts.CancelAfter(_globalTimeout);
        context.RequestAborted = cts.Token;

        try
        {
            await _next(context);
        }
        catch (OperationCanceledException) when (context.RequestAborted.IsCancellationRequested)
        {
            if (!context.Response.HasStarted)
            {
                context.Response.StatusCode = StatusCodes.Status504GatewayTimeout;
                await context.Response.WriteAsync("请求超时,请稍后重试");
            }
        }
    }
}

// 扩展方法用于注册中间件
public static class RequestTimeoutMiddlewareExtensions
{
    public static IApplicationBuilder UseGlobalRequestTimeout(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<RequestTimeoutMiddleware>();
    }
}

2. 在Program.cs中注册中间件

var builder = WebApplication.CreateBuilder(args);

// 注册服务(如IAdService、日志等)
builder.Services.AddScoped<IAdService, AdService>();
builder.Services.AddControllers();

var app = builder.Build();

// 在路由中间件之后、授权中间件之前注册超时中间件
app.UseRouting();
app.UseGlobalRequestTimeout();
app.UseAuthorization();

app.MapControllers();

app.Run();

关键说明

  • 进程内托管模式下,ASP.NET Core完全接管请求处理,IIS的超时设置不会作用于.NET Core的请求管道,必须通过代码层面的CancellationToken实现超时控制。
  • 如果AD的异步方法不直接支持CancellationToken,一定要用Task.WhenAny将查询任务与超时任务绑定,确保超时后能终止等待并抛出取消异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 17:10:30