在实际开发中,请求超时是影响系统稳定性和用户体验的重要因素之一。尤其是在调用外部接口、执行长时间任务或高并发场景下,如果没有合理的超时控制,很容易导致线程资源耗尽甚至系统崩溃。本文将系统讲解 ASP.NET Core 中处理请求超时的几种主流方式及最佳实践。
为什么需要处理请求超时?
ASP.NET Core 默认不会自动限制请求执行时间,因为不同业务场景对响应时间要求差异很大,例如文件下载、WebSocket、长轮询等 。但如果不加控制,会带来以下问题:
- 长时间占用线程资源,影响并发能力
- 外部依赖(数据库/API)异常导致请求堆积
- 用户体验差(页面长时间无响应)
- 容易触发网关或负载均衡超时(如 504)
因此,合理设置请求超时机制非常关键。
ASP.NET Core 内置超时中间件(推荐)
.NET 7+ 提供了官方的 RequestTimeouts Middleware,这是目前最标准的解决方案。
1. 启用中间件
builder.Services.AddRequestTimeouts();
var app = builder.Build();
app.UseRequestTimeouts();
注意:如果使用 UseRouting,必须在其之后调用 。
2. 单接口设置超时
app.MapGet("/test", async (HttpContext context) =>
{
await Task.Delay(10000, context.RequestAborted);
return "OK";
}).WithRequestTimeout(TimeSpan.FromSeconds(2));
或使用特性(Controller):
[RequestTimeout(2000)]
public IActionResult Get() { ... }
3. 全局超时配置
builder.Services.AddRequestTimeouts(options =>
{
options.DefaultPolicy = new RequestTimeoutPolicy
{
Timeout = TimeSpan.FromSeconds(3)
};
});
所有未单独配置的接口都会使用该默认超时策略。
4. 超时后的处理机制
当请求超时:
- HttpContext.RequestAborted 会触发
- CancellationToken.IsCancellationRequested = true
- 默认返回 504 状态码(可自定义)
5. 自定义超时响应
options.DefaultPolicy = new RequestTimeoutPolicy
{
Timeout = TimeSpan.FromSeconds(2),
WriteTimeoutResponse = async context =>
{
context.Response.ContentType = "application/json";
await context.Response.WriteAsync("{\"message\":\"Request Timeout\"}");
}
};
CancellationToken 优雅终止任务(核心实践)
即使设置了超时,如果你的代码不响应取消信号,任务仍会继续执行。
正确写法:
public async Task<IActionResult> GetData(HttpContext context)
{
try
{
await Task.Delay(10000, context.RequestAborted);
}
catch (TaskCanceledException)
{
return StatusCode(408, "Request canceled");
}
return Ok();
}
关键点:
- 使用 context.RequestAborted
- 所有 I/O 操作(数据库、HTTP请求)都要传入 token
Kestrel 与网关层超时(补充)
除了应用层,服务器层也会影响超时:
1. Kestrel 限制
Kestrel 提供一些连接级别限制(如 KeepAlive、HeadersTimeout),但无法强制终止正在执行的业务代码。
2. 反向代理 / 网关
常见如:
- Nginx
- Azure App Gateway
- AWS ALB
这些通常会在固定时间后直接返回504 Gateway Timeout。
注意:此时 ASP.NET Core 仍可能继续执行任务(必须结合 CancellationToken)。
禁用或动态控制超时
1. 禁用某接口超时
app.MapGet("/longtask", [DisableRequestTimeout] async () =>
{
await Task.Delay(10000);
});
2. 动态取消超时
var feature = context.Features.Get<IHttpRequestTimeoutFeature>();
feature?.DisableTimeout();
适用于:
- 文件上传
- 长任务处理
- 流式响应
处理请求超时最佳实践
在生产环境中,建议采用组合策略:
1. 中间件控制整体超时
- 设置全局默认超时(3~10秒)
- 特殊接口单独放宽
2. 所有异步操作支持 CancellationToken
- 数据库查询
- HttpClient 请求
- 外部服务调用
3. 分层控制
- 应用层:RequestTimeout Middleware
- 服务层:CancellationToken
- 网关层:Nginx/负载均衡超时
4. 避免长阻塞操作
- 使用 async/await
- 避免同步 I/O
总结
ASP.NET Core 并不会自动帮你杀死超时请求,而是通过:
- 中间件触发超时
- CancellationToken 通知任务终止
- 应用自行决定如何处理
这也意味着真正的超时控制能力,掌握在开发者手中。