你如何在客户端(使用JavaScript)取消一个正在运行的AJAX长时间运行的MVC操作?
你如何在客户端(使用JavaScript)取消一个正在运行的AJAX长时间运行的MVC操作?
我有一个长时间运行的(4-10秒)MVC动作,通过一个AJAX调用来运行一个报告。在它运行的同时,用户可以更改参数并运行其他操作,因此在发起另一个请求之前,我会取消AJAX请求。
所以,例如(使用jQuery的例子,但是无论如何都会发生这个问题):
// 如果我们有一个活动请求,并且它尚未完成 if(dataRequest && dataRequest.readyState != 'complete') { dataRequest.abort(); } dataRequest = $.ajax(...);
客户端上看起来这个方法运行良好,但是被取消的请求仍然在服务器上运行。例如,如果报告需要10秒,我取消一个请求并开始另一个请求,那么第二个请求需要20秒。
我认为这是由于会话级别的锁定引起的:
[如果]对同一个会话进行两个并发请求(使用相同的SessionID值),第一个请求将独占会话信息。第二个请求只有在第一个请求完成后才执行。
因此,第二个请求在第一个请求完成之前无法访问会话。使用异步MVC动作似乎无法解决此问题,因为该动作仍然需要能够对会话进行更改。
是否可能在不使用AsyncController
或[SessionState(SessionStateBehavior.ReadOnly)]
的情况下停止一个动作并启动下一个动作?
如果不可能,这两个都是必需的吗?
问题的原因是ASP.Net sessions无法处理乐观并发,因此如果一个请求在执行时,其他请求必须等待。解决方法是编写自己的会话处理程序,并定期检查是否仍然连接到客户端。
以下是解决方法的代码示例:
public class CustomSessionHandler : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
// 检查是否仍然连接到客户端
if (!context.Response.IsClientConnected)
{
// 取消请求
context.Response.End();
}
else
{
// 继续处理请求
// ...
}
}
public bool IsReusable
{
get { return false; }
}
}
在这个示例中,我们创建了一个名为CustomSessionHandler的自定义会话处理程序。在ProcessRequest方法中,我们检查Response的IsClientConnected属性。如果客户端不再连接,我们结束响应,取消请求。否则,我们继续处理请求。
请注意,检查IsClientConnected属性可能会对性能产生影响。因此,在使用时应谨慎使用。
希望以上代码示例能够帮助你解决问题!
问题的原因是,当在客户端取消AJAX长时间运行的MVC操作时,使用.abort()方法只能在客户端取消。如果想要在服务器端监控取消操作,可以通过轮询IsClientConnected属性来获取AJAX通信的状态。
解决方法是,使用.poll()方法来监控IsClientConnected属性,并根据其状态来判断AJAX通信的状态。具体实现可以参考问题的原始提问和已经得到的回答。需要注意的是,使用IsClientConnected属性可能会导致严重的性能问题,因为检查该属性可能需要占用较长的时间。
以下是原始回答中的一段代码示例:
var xhr = $.ajax({ url: "yourUrl", type: "POST", data: "yourData", success: function(result) { // handle success }, error: function(xhr, status, error) { if (status === "abort") { // handle cancellation } else { // handle other errors } } }); // cancel the AJAX request xhr.abort();
希望这个解决方法能够帮助到你。
问题的出现的原因:需要在客户端(javascript)取消一个长时间运行的MVC操作。
解决方法:在服务器端关联每个任务一个唯一的id,并在启动新任务时将此任务id返回给客户端。然后,当在客户端调用.abort()取消AJAX请求时,可以向其他控制器动作发出另一个AJAX请求,并传递唯一的任务id。这个控制器动作本身将设置一个公共标志,指示第一个操作停止。
TPL具有内置的取消支持,可以简化这一过程,以避免两个任务之间的共享数据结构来进行同步。
已经使用TPL来执行大部分耗时的工作,以并行方式执行大约25秒的长时间运行代码,而在4-10秒内完成。然而,使用它来处理中止似乎是重新发明轮子;为什么新的请求需要告诉旧的(仍在运行)请求中止,当它已经被取消了?
不是新的请求告诉旧的请求中止。你必须发送一个特殊的新的AJAX请求,告诉服务器中止处理特定的任务。当你执行dataRequest.abort()时,只是中止了AJAX请求,但是如果你想中止服务器端的处理,就需要做更多的工作。
IIS知道请求在传输层被取消了吗?当在传输层中断等待的连接时,我希望IIS/ASP级别的页面线程会被中止。
IIS确实知道-我只需要在长时间运行的页面中检查Response.IsClientConnected属性。当该属性变为false时,我取消正在进行的操作。