前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >.NET Core使用 CancellationToken 取消API请求

.NET Core使用 CancellationToken 取消API请求

作者头像
Chester Chen
发布2024-03-25 13:59:10
670
发布2024-03-25 13:59:10
举报
文章被收录于专栏:chester技术分享chester技术分享

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

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

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

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

长时间运行的任务请求

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

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

代码语言:javascript
复制
[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 注入到操作方法中,并通过其取消不必要的操作。

代码语言:javascript
复制
[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 捕获,或者通过一个过滤器统一监视此异常。

代码语言:javascript
复制
public class OperationCancelledExceptionFilter : ExceptionFilterAttribute
{
    private readonly ILogger _logger;

    public OperationCancelledExceptionFilter(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<OperationCancelledExceptionFilter>();
    }
    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<OperationCancelledExceptionFilter>();
});
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-03-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 chester技术分享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档