.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
相关产品推荐
相关产品推荐

