.NET Core利用 CancellationToken 取消API请求

打印 上一主题 下一主题

主题 828|帖子 828|积分 2499

您是否曾经访问过一个网站,它需要很长时间加载,最终你敲击 F5 重新加载页面。
即利用户刷新了欣赏器取消了原始请求,而对于服务器来说,API也不会知道它正在计算的值将在结束时被抛弃,刷新五次,服务器将触发 5 个请求。
为了办理这个问题,ASP.NET Core 为 Web 服务器提供了一种机制,就是CancellationToken.
用户取消请求时,你可以利用HttpContext.RequestAborted访问,您也可以利用依赖注入将其自动注入到您的操作中。
 
长时间运行的使命请求
现在我们假设您有一个 API 操作,在向用户发送响应之前可能需要一些时间才能完成。
在处理该操作时,用户可以直接取消请求,或刷新页面(这会有用地取消原始请求,并启动新请求)。
  1. [HttpGet(Name = "get")]
  2. public async Task<string> GetAsync()
  3. {
  4.     try
  5.     {
  6.         _logger.LogInformation("request in");
  7.         await Task.Delay(5 * 1000);
  8.         _logger.LogInformation("request end");
  9.     }
  10.     catch (Exception ex)
  11.     {
  12.         _logger.LogInformation("request ex");
  13.     }
  14.     return "ok";
  15. }
复制代码
假如用户在请求中途刷新欣赏器,那么欣赏器永久不会收到第一个请求的响应,但在server端可以看到,操作方法执行完成两次。

这是否是正确将取决于您的应用程序。
假如请求修改某些业务的状态,那么您可能不希望在方法中途制止执行。假如请求没有副作用,那么您可能希望尽快制止(可能很昂贵)操作。
用户取消请求时,你可以利用HttpContext.RequestAborted访问,您也可以利用依赖注入将其自动注入到您的操作中。
 
CancellationTokens取消不必要的请求
以下代码显示了如何通过将 CancellationTokenSource 注入到操作方法中,并通过其取消不必要的操作。
  1. [HttpGet(Name = "get")]
  2. public async Task<string> GetAsync(CancellationToken cancellationToken)
  3. {
  4.     try
  5.     {
  6.         _logger.LogInformation("request in");
  7.         await Task.Delay(5 * 1000,cancellationToken);
  8.         _logger.LogInformation("request end");
  9.     }
  10.     catch (Exception ex)
  11.     {
  12.         _logger.LogInformation("request ex");
  13.     }
  14.     return "ok";
  15. }
复制代码
通过这个改变,我们可以再次测试我们的场景。
我们发出一个初始请求,然后我们重新加载页面。正如您从下面的日记中看到的,第一个请求不会继续执行。

用户刷新欣赏器取消请求后不久,原始请求就会中止,并TaskCancelledException通过 API 过滤器管道传播回来,并备份中间件管道。
根据您的场景,您可能能够依靠此类框架方法来检查 的状态CancellationToken,或者您可能需要本身监视取消请求。
 
过滤器捕捉异常
您可以通过以上try catch 捕捉,或者通过一个过滤器同一监视此异常。
  1. public class OperationCancelledExceptionFilter : ExceptionFilterAttribute
  2. {
  3.     private readonly ILogger _logger;
  4.     public OperationCancelledExceptionFilter(ILoggerFactory loggerFactory)
  5.     {
  6.         _logger = loggerFactory.CreateLogger<OperationCancelledExceptionFilter>();
  7.     }
  8.     public override void OnException(ExceptionContext context)
  9.     {
  10.         if (context.Exception is OperationCanceledException)
  11.         {
  12.             _logger.LogInformation("Request was cancelled");
  13.             context.ExceptionHandled = true;
  14.             context.Result = new StatusCodeResult(400);
  15.         }
  16.     }
  17. }
  18. builder.Services.AddControllers(options =>
  19. {
  20.     options.Filters.Add<OperationCancelledExceptionFilter>();
  21. });
  22. <br>
复制代码

 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

大连全瓷种植牙齿制作中心

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表