• .NET Core使用 CancellationToken 取消API请求


    您是否曾经访问过一个网站,它需要很长时间加载,最终你敲击 F5 重新加载页面。

    即使用户刷新了浏览器取消了原始请求,而对于服务器来说,API也不会知道它正在计算的值将在结束时被丢弃,刷新五次,服务器将触发 5 个请求。

    为了解决这个问题,ASP.NET Core 为 Web 服务器提供了一种机制,就是CancellationToken.

    用户取消请求时,你可以使用HttpContext.RequestAborted访问,您也可以使用依赖注入将其自动注入到您的操作中。

     

    长时间运行的任务请求

    现在我们假设您有一个 API 操作,在向用户发送响应之前可能需要一些时间才能完成。

    在处理该操作时,用户可以直接取消请求,或刷新页面(这会有效地取消原始请求,并启动新请求)。

    复制代码
    [HttpGet(Name = "get")]
    public async Task<string> GetAsync()
    {
        try
        {
            _logger.LogInformation("request in");
            await Task.Delay(5 * 1000);
            _logger.LogInformation("request end");
        }
        catch (Exception ex)
        {
            _logger.LogInformation("request ex");
        }
        return "ok";
    }
    复制代码

    如果用户在请求中途刷新浏览器,那么浏览器永远不会收到第一个请求的响应,但在server端可以看到,操作方法执行完成两次。

    这是否是正确将取决于您的应用程序。

    如果请求修改某些业务的状态,那么您可能不希望在方法中途停止执行。如果请求没有副作用,那么您可能希望尽快停止(可能很昂贵)操作。

    用户取消请求时,你可以使用HttpContext.RequestAborted访问,您也可以使用依赖注入将其自动注入到您的操作中。

     

    CancellationTokens取消不必要的请求

    以下代码显示了如何通过将 CancellationTokenSource 注入到操作方法中,并通过其取消不必要的操作。

    复制代码
    [HttpGet(Name = "get")]
    public async Task<string> GetAsync(CancellationToken cancellationToken)
    {
        try
        {
            _logger.LogInformation("request in");
            await Task.Delay(5 * 1000,cancellationToken);
            _logger.LogInformation("request end");
        }
        catch (Exception ex)
        {
            _logger.LogInformation("request ex");
        }
        return "ok";
    }
    复制代码

    通过这个改变,我们可以再次测试我们的场景。

    我们发出一个初始请求,然后我们重新加载页面。正如您从下面的日志中看到的,第一个请求不会继续执行。

    用户刷新浏览器取消请求后不久,原始请求就会中止,并TaskCancelledException通过 API 过滤器管道传播回来,并备份中间件管道。

    根据您的场景,您可能能够依靠此类框架方法来检查 的状态CancellationToken,或者您可能需要自己监视取消请求。

     

    过滤器捕获异常

    您可以通过以上try catch 捕获,或者通过一个过滤器统一监视此异常。

    复制代码
    public class OperationCancelledExceptionFilter : ExceptionFilterAttribute
    {
        private readonly ILogger _logger;
    
        public OperationCancelledExceptionFilter(ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger();
        }
        public override void OnException(ExceptionContext context)
        {
            if (context.Exception is OperationCanceledException)
            {
                _logger.LogInformation("Request was cancelled");
                context.ExceptionHandled = true;
                context.Result = new StatusCodeResult(400);
            }
        }
    }
    
    
    builder.Services.AddControllers(options =>
    {
        options.Filters.Add();
    });
    
    复制代码

     


  • 相关阅读:
    数据结构《LinkeList 双向链表》
    java中“冷门”工具类的总结
    java计算机毕业设计校园二手交易网站源码+系统+数据库+lw文档+mybatis+运行部署
    Swift - 泛型
    LeetCode78.子集
    重测序基因组:Pi核酸多样性计算
    在应用程序中添加shell 执行命令脚本
    司徒理财:10.26周四黄金走势分析,黄金操作策略,谨慎追多
    角互补三角形面积公式的证明过程
    【老生谈算法】matlab实现三相短路电流计算源码——短路电流
  • 原文地址:https://www.cnblogs.com/chenyishi/p/18075600