用于限制API执行时间的TimeoutAttribute实现异常排查
问题排查与修正方案
你的TimeoutAttribute未能按预期工作,核心问题有以下几点:
1. 时间单位错误
构造函数中错误地将毫秒参数传给了TimeSpan.FromSeconds,导致超时时间被放大1000倍。例如传入5000(期望5秒超时),实际会设置5000秒(约1小时23分)的超时,完全无法触发预期的超时逻辑。
修正:将TimeSpan.FromSeconds改为TimeSpan.FromMilliseconds。
2. 拦截时机错误
你重写的OnActionExecutingAsync是Action执行前的钩子方法,基类的base.OnActionExecutingAsync是空实现,当前代码的超时控制只作用于这个空方法,完全没有覆盖到实际的API接口业务逻辑执行环节,因此超时逻辑根本不会影响Action的执行。
3. 未正确包裹Action执行过程
要实现Action的超时控制,必须将Action的执行逻辑纳入超时监控范围内,而不是仅给过滤器的前置方法加超时。
修正后的完整代码示例
public class TimeoutAttribute : ActionFilterAttribute { private readonly TimeSpan _timeout; public TimeoutAttribute(int timeoutInMilliseconds) { // 修正时间单位:使用毫秒转换为TimeSpan _timeout = TimeSpan.FromMilliseconds(timeoutInMilliseconds); } public override async Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken) { using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) { cts.CancelAfter(_timeout); try { // 手动触发Action执行,并将超时令牌传入,控制执行过程 var actionResult = await actionContext.ActionDescriptor.ExecuteAsync( actionContext.ControllerContext, actionContext.ActionArguments, cts.Token); // 生成成功响应 actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, actionResult); } catch (OperationCanceledException) { // 触发超时返回408 actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.RequestTimeout, ApiErrorMessages.RequestTimeout); } catch (Exception ex) { // 处理其他异常 actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message); } } } }
额外注意事项
- 如果你的Action内部包含异步操作,需要确保这些异步方法正确响应传入的
CancellationToken,否则即使触发超时,后台任务可能仍会继续执行。 - 若要避免后台任务泄漏,可以在超时触发后,确保所有异步操作都能被正确取消。
内容的提问来源于stack exchange,提问作者Kaushik Thanki
相关产品推荐
相关产品推荐

