FastEndpoints是否支持为所有端点设置全局请求超时?
FastEndpoints 请求超时与 CancellationToken 触发问题解答
CancellationToken 触发的常见原因
你观察到的 CancellationToken 触发,最常见的原因确实是客户端主动断开连接(比如用户关闭浏览器、APP退出或网络中断)。除此之外,也可能是请求处理流程中主动调用了取消逻辑,或者后续中间件/业务代码触发了取消,但客户端断开是最普遍的场景。
FastEndpoints 的请求超时支持
FastEndpoints 本身没有内置的请求超时功能,但它基于 ASP.NET Core 构建,因此可以直接利用 ASP.NET Core 的原生机制来实现请求超时,包括全局配置和单个端点配置。
全局请求超时的实现方式
以下是两种常用的全局超时配置方案:
1. Kestrel 层面全局超时
直接在 Kestrel 服务器配置中设置请求超时,超过指定时间后服务器会主动断开连接,触发 CancellationToken:
builder.WebHost.ConfigureKestrel(options => { // 设置全局请求超时为30秒 options.Limits.RequestTimeout = TimeSpan.FromSeconds(30); });
这种方式是最底层的超时控制,所有经过 Kestrel 的请求都会生效。
2. 自定义中间件实现全局超时
如果需要自定义超时后的响应内容(比如返回特定的错误JSON),可以编写一个全局中间件来包裹请求:
// 先定义超时配置选项 public class RequestTimeoutOptions { public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(30); } // 自定义超时中间件 public class RequestTimeoutMiddleware { private readonly RequestDelegate _next; private readonly TimeSpan _timeout; public RequestTimeoutMiddleware(RequestDelegate next, IOptions<RequestTimeoutOptions> options) { _next = next; _timeout = options.Value.Timeout; } public async Task InvokeAsync(HttpContext context) { // 关联原有请求取消令牌和超时令牌 using var timeoutCts = new CancellationTokenSource(_timeout); using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(context.RequestAborted, timeoutCts.Token); context.RequestAborted = linkedCts.Token; try { await _next(context); } catch (OperationCanceledException) when (timeoutCts.IsCancellationRequested) { // 超时触发时返回408状态码和自定义响应 context.Response.StatusCode = StatusCodes.Status408RequestTimeout; context.Response.ContentType = "application/json"; await context.Response.WriteAsync("{\"error\":\"请求超时,请稍后重试\"}"); } } } // 注册配置和中间件 builder.Services.Configure<RequestTimeoutOptions>(options => { options.Timeout = TimeSpan.FromSeconds(30); }); // 注意中间件要放在FastEndpoints中间件之前 builder.UseMiddleware<RequestTimeoutMiddleware>(); builder.UseFastEndpoints();
单个端点的超时控制
如果只需要给特定端点设置超时,可以在端点的处理逻辑中创建关联的取消令牌:
public class OrderProcessingEndpoint : Endpoint<OrderRequest, OrderResponse> { public override void Configure() { Post("/api/orders/process"); AllowAnonymous(); } public override async Task HandleAsync(OrderRequest req, CancellationToken ct) { // 设置当前端点的超时为20秒,关联原有取消令牌 using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(ct); timeoutCts.CancelAfter(TimeSpan.FromSeconds(20)); try { // 将timeoutCts.Token传入耗时操作 var result = await OrderService.ProcessAsync(req.OrderId, timeoutCts.Token); await SendAsync(result); } catch (OperationCanceledException) when (timeoutCts.IsCancellationRequested) { await SendAsync(new OrderResponse { Success = false, Message = "订单处理超时" }, 408); } } }
内容的提问来源于stack exchange,提问作者andrew pate
相关产品推荐
相关产品推荐

