我编写了以下MVC控制器来测试取消功能:
class MyController : Controller
{
[HttpGet("api/CancelTest")]
async Task<IActionResult> Get()
{
await Task.Delay(1000);
CancellationToken token = HttpContext.RequestAborted;
bool cancelled = token.IsCancellationRequested;
logger.LogDebug(cancelled.ToString());
return Ok();
}
}
说,我想取消请求,因此值&#39; true &#39;记录在上面的控制器操作中。如果服务器实现IHttpRequestLifetimeFeature,这可能是服务器端。幸运的是,Kestrel确实如此,这可以通过以下方式实现:
var feature = (IHttpRequestLifetimeFeature) HttpContext.Features[typeof(IHttpRequestLifetimeFeature)];
feature.Abort();
但问题是我想取消客户端的请求。例如,在浏览器中。在ASP.NET MVC / WebApi的预核版本中,如果浏览器中止请求,则取消令牌将自动取消。示例:在Chrome中多次刷新页面。在chrome dev工具的“网络”选项卡中,您现在可以看到上一个(未完成的)请求被取消。
问题是:在Kestrel上运行的ASP.NET Core中,我只能在日志中看到以下条目:
Microsoft.AspNetCore.Server.Kestrel.Internal.Networking.UvException: 错误-4081 ECANCELED操作已取消
因此来自浏览器的中止请求到达并由Kestrel网络服务器处理。但它不会影响控制器中HttpContext的RequestAborted属性,因为值&#39; false &#39;仍然按方法记录。
问题: 有没有办法中止/取消我的控制器的方法,以便HttpContext.RequestAborted属性将被标记为已取消?
也许我可以制作一些可以订阅Kestrel操作取消触发器并调用IHttpRequestLifetimeFeature.Abort()方法的东西?
更新 我做了一些进一步的测试,似乎HttpRequest IS 实际上已经中止了,但在实际取消之前似乎有某种延迟。延迟不是时间因素,似乎直接来自libuv(Kestrel网络服务器构建在其上的库)。我在https://github.com/aspnet/KestrelHttpServer/issues/1103
上发布了更多信息更多更新: 问题已转移到另一个问题,因为前一个问题包含多个问题。 https://github.com/aspnet/KestrelHttpServer/issues/1139
答案 0 :(得分:3)
事实证明,简单地使用HttpContext.RequestAborted确实是正确的方法,但是由于Kestrel中的错误(处理FIN / RST包的顺序),请求在浏览器中止时没有中止。
最终应该在Kestrel 2.0中修复错误。
有关详细信息,请参阅我的问题中的更新。