MVC下请求无法取消,点击取消后第二次请求延迟到达问题咨询
问题根因
- 控制器参数类型错误:ASP.NET Core 默认只会将客户端断开触发的取消信号注入到
CancellationToken类型参数,你当前使用CancellationTokenSource作为参数,无法正确接收到前端取消请求的信号。 - 前端取消逻辑不完整:仅隐藏加载图标未真正终止AJAX请求,服务端仍会继续执行耗时的视图绑定逻辑;同时浏览器对同域名的并发请求有配额限制(通常为6个),未终止的旧请求占用了连接池,新请求只能排队等待,就是你遇到的等待1分钟才进入控制器的原因。
BindResultToPartialView方法内部未检查取消令牌,就算拿到取消信号也会跑完整个渲染流程,持续占用服务端资源。
后端修改方案
- 调整控制器参数类型,改为框架自动注入的
CancellationToken,渲染前先检查是否已取消:
public async Task<IActionResult> Get(CancellationToken cancellationToken) { var rng = new Random(); var res = Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }) .ToArray(); // 渲染前先校验取消信号,提前终止流程 cancellationToken.ThrowIfCancellationRequested(); return await BindResultToPartialView(res, cancellationToken); }
- 改造
BindResultToPartialView方法,在耗时的绑定逻辑(比如遍历数据生成网格行)中添加取消校验:
private async Task<IActionResult> BindResultToPartialView<T>(T data, CancellationToken cancellationToken) { // 入口先校验取消信号 cancellationToken.ThrowIfCancellationRequested(); // 遍历绑定时每轮都校验 if (data is IEnumerable enumerableData) { foreach (var item in enumerableData) { cancellationToken.ThrowIfCancellationRequested(); // 原有行绑定逻辑 } } // 剩余渲染逻辑 }
前端修改方案
全局存储当前请求的实例,发起新请求或者用户点击取消按钮时,主动调用abort()终止旧请求,释放连接池配额:
原生JS实现
// 全局存储当前请求实例 let currentGetRequest = null; // 拉取数据方法 function loadGridData() { // 发起新请求前先终止上一个未完成的请求 if (currentGetRequest) { currentGetRequest.abort(); currentGetRequest = null; } currentGetRequest = new XMLHttpRequest(); currentGetRequest.open('GET', '/你的控制器名称/Get', true); currentGetRequest.onload = function() { if (currentGetRequest.status === 200) { // 替换局部视图的逻辑 } currentGetRequest = null; }; currentGetRequest.onabort = currentGetRequest.onerror = function() { currentGetRequest = null; // 隐藏加载图标的逻辑 }; currentGetRequest.send(); } // 取消按钮点击事件 document.getElementById('你的取消按钮ID').addEventListener('click', function() { if (currentGetRequest) { currentGetRequest.abort(); } // 隐藏加载图标的逻辑 });
jQuery AJAX实现
let currentGetRequest = null; function loadGridData() { if (currentGetRequest) { currentGetRequest.abort(); } currentGetRequest = $.ajax({ url: '/你的控制器名称/Get', type: 'GET', success: function (res) { // 替换局部视图的逻辑 }, complete: function () { currentGetRequest = null; } }); } $('#你的取消按钮ID').on('click', function() { if (currentGetRequest) { currentGetRequest.abort(); } // 隐藏加载图标的逻辑 });
内容的提问来源于stack exchange,提问作者Deepak
相关产品推荐
相关产品推荐

