Asp.net核心中间件,如果花费很长时间,则取消请求 [英] Asp.net Core Middleware that cancel a request if taking to long

查看:54
本文介绍了Asp.net核心中间件,如果花费很长时间,则取消请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我的api花费的时间超过x的时间,我需要一个中间件来取消请求.我所有的api调用都是可以取消的:

I need a middleware to cancel a request if my api is taking more than x amount of time. All my api calls are asynch and cancellable:

public async Task<IActionResult> Get(CancellationToken token) {  }

... 

public async Task InvokeAsync(HttpContext context)
{
    //....
    int customDurationMilis = 1000; //1second

    cancellTimer = new Timer(CancellRequestCallBack, context, customDurationMilis, Timeout.Infinite);
    //...

    await _next(context);
}

private void CancellRequestCallBack(HttpContext context)
{
    //log...
    //Aborts the connection underlying this request.
    context.Abort();
}

想象我有一个api操作方法需要2秒钟,计时器将触发正在进行连接中止的CancellRequestCallBack.拥有计时器是个好主意吗?还是应该采用另一种方法?如何返回自定义错误代码而不是context.Abort()并取消正在进行的api调用?一些想法将不胜感激.谢谢

imagine I have an api action method taking 2 seconds, the timer will trigger the CancellRequestCallBack which is doing a connection abort. Is good idea to have a Timer? or should go with another approach? How to return a custom error code instead of context.Abort() and cancel the ongoing api call? some ideas will be very much appreciate. thanks

更新,尝试这样做:

public async Task InvokeAsync(HttpContext context)
{
    var task = _next(context);

    if (await Task.WhenAny(task, Task.Delay(1000)) != task)
    {
        throw new MyCustomException("timeout!");
    }
}

至少我在errorhandlerMiddleware中捕获了返回状态代码500的异常.但是我没有在Postman中得到它.相反,我越来越无法得到任何回应"而且我猜带有请求的线程仍将运行.

at least with this I catch the exception in errorhandlermiddleware returning a status code 500. But I don;t get it in Postman. Instead I am getting "Could not get any response" Also the thread with the request will still run I guess.

推荐答案

实际上由于以下几个原因很难实现:

This is actually pretty difficult to implement for a couple of reasons:

  • 取消是合作的.这意味着您需要(暂时)等待的所有事情都可以尊重令牌.
  • 保持异步状态意味着没有线程可以中止.您可以中止整个TCP连接,但是如果没有人在听令牌并且没有人在阅读正文,它将不会对正在运行的服务器代码产生任何作用.
  • 使用 Task.WhenAny 并不是一个好的解决方案,因为您可能最终会并行使用 HttpContext .您已取消"的代码可能即将在中间件试图编写超时响应的同时编写一个有效的响应.即使抛出异常,也是很危险的,因为还有其他正在运行的代码可能同时触及 HttpContext .
  • Cancellation is cooperative. This means you need everything you're awaiting (transitively) to respect the token.
  • Being async means there's no thread to abort. You can abort the entire TCP connection but if nobody is listening to the token and nobody is reading the body, it won't do anything to the running server code.
  • Using Task.WhenAny isn't a good solution because you might end up using the HttpContext in parallel. The code you "cancelled" might be about to write a valid response at the same time your middleware is trying to write a timeout response. Even if you throw an exception, it's dangerous because there's other running code that might be touching the HttpContext in parallel.

您可以冒险,但是可能存在细微的比赛条件,这些情况会导致事情以意外的方式失败.

You can risk it, but there might be subtle race conditions that cause things to fail in unexpected ways.

如果您遵守取消令牌,则只需取消令牌并等待下一个撤销.完成后,您可以在写入响应之前查看响应是否已经开始,并返回408(请求超时).

If you're respecting cancellation tokens, then you can just cancel the token and wait for next to unwind. When it does, then you can see if the response has started before writing to it and return a 408 (request timed out).

这篇关于Asp.net核心中间件,如果花费很长时间,则取消请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆