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

.NET 8升级后ASP.NET Core长轮询超时致服务端性能问题求助

解决方案:处理.NET 8长轮询超时导致的服务端异常与性能问题

针对.NET 8升级后长轮询场景下服务端频繁抛出OperationCanceledException、记录499状态码并引发性能下降的问题,可通过以下几种方式解决:

1. 自定义中间件捕获并处理客户端断开异常

通过中间件拦截客户端断开导致的取消异常,仅记录信息日志而非错误日志,避免异常指标膨胀:

public class ClientDisconnectHandlerMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<ClientDisconnectHandlerMiddleware> _logger;

    public ClientDisconnectHandlerMiddleware(RequestDelegate next, ILogger<ClientDisconnectHandlerMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (OperationCanceledException)
        {
            // 判断是否为客户端主动断开(未发送响应前的请求中止)
            if (context.RequestAborted.IsCancellationRequested && !context.Response.HasStarted)
            {
                context.Response.StatusCode = 499;
                _logger.LogInformation("Long-polling request canceled by client (status 499)");
                return;
            }
            // 非客户端断开的取消异常正常抛出
            throw;
        }
    }
}

// 在Program.cs中注册中间件(需放在异常处理中间件之前)
app.UseMiddleware<ClientDisconnectHandlerMiddleware>();

2. 过滤客户端断开相关的日志

如果不想修改请求处理逻辑,可通过自定义日志过滤器屏蔽这类异常日志:

方式一:自定义日志过滤类

public class IgnoreClientDisconnectFilter : ILogFilter
{
    public bool IsEnabled(LogEntry logEntry)
    {
        // 过滤掉客户端断开导致的OperationCanceledException日志
        return !(logEntry.Exception is OperationCanceledException && 
                 logEntry.Message.Contains("The request was aborted"));
    }
}

// 在Program.cs注册过滤器
builder.Services.AddLogging(config =>
{
    config.AddFilter<IgnoreClientDisconnectFilter>();
});

方式二:配置文件过滤(针对Kestrel相关日志)

在appsettings.json中调整日志级别,减少Kestrel对断开连接的日志输出:

{
  "Logging": {
    "LogLevel": {
      "Microsoft.AspNetCore.Server.Kestrel": "Warning"
    }
  }
}

3. 优化Kestrel连接配置

调整Kestrel的超时参数,避免连接队列无限制膨胀:

builder.WebHost.ConfigureKestrel(options =>
{
    // 设置空闲连接超时,根据业务场景调整
    options.Limits.IdleTimeout = TimeSpan.FromMinutes(3);
    // 设置请求头接收超时
    options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(30);
});

4. 替换长轮询实现(可选)

如果业务允许,改用SignalR实现实时通信,SignalR在.NET 8中对客户端断开、超时的处理更成熟,能原生避免这类异常问题,同时提升通信效率。

问题根源说明

.NET 8对Kestrel的请求取消逻辑进行了升级,将客户端主动断开(包括长轮询超时)的场景统一标记为OperationCanceledException并返回499状态码,目的是更精准地追踪请求生命周期,但与旧版本的行为不一致,导致长轮询场景下异常日志和性能问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 03:46:10