ASP.NET Core MVC 中浏览器中止时 HttpRequest 未中止(取消)

HttpRequest not aborted (cancelled) on browser abort in ASP.NET Core MVC

我编写了以下 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();
    }
}

说,我想取消请求,所以值 'true' 被记录在上面的控制器操作中。如果服务器实现了 IHttpRequestLifetimeFeature,这在服务器端是可能的。幸运的是,Kestrel 做到了,这可以通过以下方式完成:

var feature = (IHttpRequestLifetimeFeature) HttpContext.Features[typeof(IHttpRequestLifetimeFeature)];
feature.Abort();

但是问题是我想在客户端取消请求。例如,在浏览器中。在 ASP.NET MVC/WebApi 的预核心版本中,如果浏览器中止请求,取消令牌将自动取消。示例:在 Chrome 中刷新页面几次。在 chrome 开发工具的“网络”选项卡中,您现在可以看到之前(未完成的)请求已被取消。

问题是:在 ASP.NET Core 运行 on Kestrel 中,我只能在日志中看到以下条目:

Microsoft.AspNetCore.Server.Kestrel.Internal.Networking.UvException: Error -4081 ECANCELED operation canceled

因此来自浏览器的中止请求确实到达并由 Kestrel 网络服务器处理。但是,它不会影响控制器中 HttpContext 的 RequestAborted 属性,因为该方法仍会记录值“false”。

问题: 有没有办法 abort/cancel 我的控制器的方法,以便 HttpContext.RequestAborted 属性 将被标记为已取消?

也许我可以制作一些订阅 Kestrel 操作取消的触发器并调用 IHttpRequestLifetimeFeature.Abort() 方法?

更新: 我做了一些进一步的测试,似乎 HttpRequest IS 实际上中止了,但在取消实际发生之前似乎有某种延迟。延迟不是时间因素,似乎直接来自 libuv(Kestrel 网络服务器构建于其上的库)。我在 https://github.com/aspnet/KestrelHttpServer/issues/1103

上发布了更多信息

更多更新: 问题已移至另一个,因为前一个包含多个问题。 https://github.com/aspnet/KestrelHttpServer/issues/1139

事实证明,简单地使用 HttpContext.RequestAborted 确实是正确的方法,但是由于 Kestrel 中的错误(处理 FIN/RST 包的顺序),请求没有中止浏览器中止。

该错误最终应在 Kestrel 2.0 中修复。

查看我问题中的更新以获取更多信息。