为什么同一个ASP.NET MVC操作的多个同时AJAX调用会导致浏览器阻塞?

Kev*_*Kev 73 javascript ajax asp.net-mvc jquery asp.net-mvc-2

几天前我问了这个问题:

为什么$ .getJSON()会阻止浏览器?

我在同一个控制器动作中同时发出六个jQuery async ajax请求.每个请求需要10秒才能返回.

通过调试和记录对action方法的请求,我注意到请求是序列化的,并且永远不会并行运行.即我在我的log4net日志中看到一个时间轴,如下所示:

2010-12-13 13:25:06,633 [11164] INFO   - Got:1156
2010-12-13 13:25:16,634 [11164] INFO   - Returning:1156
2010-12-13 13:25:16,770 [7124] INFO   - Got:1426
2010-12-13 13:25:26,772 [7124] INFO   - Returning:1426
2010-12-13 13:25:26,925 [11164] INFO   - Got:1912
2010-12-13 13:25:36,926 [11164] INFO   - Returning:1912
2010-12-13 13:25:37,096 [9812] INFO   - Got:1913
2010-12-13 13:25:47,098 [9812] INFO   - Returning:1913
2010-12-13 13:25:47,283 [7124] INFO   - Got:2002
2010-12-13 13:25:57,285 [7124] INFO   - Returning:2002
2010-12-13 13:25:57,424 [11164] INFO   - Got:1308
2010-12-13 13:26:07,425 [11164] INFO   - Returning:1308

查看FireFox中的网络时间线,我看到了:

替代文字

上面的日志示例和Firefox网络时间线都针对同一组请求.

来自同一页面的同一操作的请求是否已序列化?我知道Session在同一会话中对对象的序列化访问,但没有触及会话数据.

我将客户端代码剥离为单个请求(运行时间最长)但仍会阻止浏览器,即只有当ajax请求完成时,浏览器才会响应任何链接点击.

我在这里(在Chrome的开发人员工具中)观察到的是,在执行长时间运行的ajax请求时单击链接时,它会Failed to load resource立即报告错误,这表明浏览器已经杀死(或者正试图杀死并等待?)ajax请求:

替代文字

但是,浏览器仍需要一个年龄才能重定向到新页面.

ajax请求是否真的是异步的,或者这很简单,因为javascript实际上是单线程的?

我的要求是否需要花费太长时间才能完成这项工作?

问题也出现在Firefox和IE中.

我还将脚本更改为$.ajax直接使用并明确设置async: true.

我在IIS7.5上运行它,Windows 2008R2和Windows 7版本都做同样的事情.

调试和发布版本的行为也相同.

Kev*_*Kev 89

答案是盯着我的脸.

ASP.NET会话状态概述:

对会话状态的访问是每个会话独占的,这意味着如果两个不同的用户发出并发请求,则同时授予对每个单独会话的访问权限.但是,如果对同一会话发出两个并发请求(通过使用相同的SessionID值),则第一个请求将获得对会话信息的独占访问权.第二个请求仅在第一个请求完成后执行.

令人讨厌的是,几周前我已经撇去了一段并没有真正考虑到大胆句子的全部影响.我已经读过,只是"访问会话状态是序列化的"而不是"所有请求,无论你是否触摸会话状态,都被序列化",如果请求来自同一个会话.

幸运的是,ASP.NET MVC3中有一个可行的方法,它可以创建无会话控制器.Scott Guthrie在这里谈到这些:

宣布ASP.NET MVC 3(候选发布者2)

我安装了MVC3 RC2并升级了项目.装饰有问题的控制器[SessionState(SessionStateBehavior.Disabled)]解决了这个问题.

当然,通常我几分钟前在Stack Overflow中发现了这个:

异步控制器通过jQuery阻止ASP.NET MVC中的请求

  • 请注意,使用`[SessionState(SessionStateBehavior.Disabled)]`可能会在您的应用程序中打开安全漏洞,例如在多个同时请求中访问私有数据,使用此选项您无法知道用户是否已记录,也不是会话是活动的等等...如果你需要访问会话你可以使用`[SessionState(SessionStateBehavior.ReadOnly)]`,所以你仍然可以访问你的会话,虽然你不能编辑它,但仍然可以在许多情况下帮助. (6认同)

Dar*_*rov 9

我试图重现这个但是无法重现.这是我的测试:

private static readonly Random _random = new Random();

public ActionResult Ajax()
{
    var startTime = DateTime.Now;
    Thread.Sleep(_random.Next(5000, 10000));
    return Json(new { 
        startTime = startTime.ToString("HH:mm:ss fff"),
        endTime = DateTime.Now.ToString("HH:mm:ss fff") 
    }, JsonRequestBehavior.AllowGet);
}
Run Code Online (Sandbox Code Playgroud)

电话:

<script type="text/javascript" src="/scripts/jquery-1.4.1.js"></script>
<script type="text/javascript">
    $(function () {
        for (var i = 0; i < 6; i++) {
            $.getJSON('/home/ajax', function (result) {
                $('#result').append($('<div/>').html(
                    result.startTime + ' | ' + result.endTime
                ));
            });
        }
    });
</script>

<div id="result"></div>
Run Code Online (Sandbox Code Playgroud)

结果如下:

13:37:00 603 | 13:37:05 969
13:37:00 603 | 13:37:06 640
13:37:00 571 | 13:37:07 591
13:37:00 603 | 13:37:08 730
13:37:00 603 | 13:37:10 025
13:37:00 603 | 13:37:10 166
Run Code Online (Sandbox Code Playgroud)

和FireBug控制台:

替代文字

正如您所看到的,AJAX操作是并行执行的.


更新:

似乎在我的初始测试中,使用时,请求确实在FireFox 3.6.12和Chrome 8.0.552.215中排队$.getJSON().它在IE8中工作正常.我的测试是使用ASP.NET MVC 2项目,VS2010,Cassini Web服务器,Windows 7 x64位执行的.

现在,如果我更换$.getJSON()$.get()它在所有的浏览器工作正常.这让我相信这有$.getJSON()可能导致请求排队的东西.也许更熟悉jQuery框架内部的人能够更多地了解这个问题.


更新2:

尝试设置cache: false:

$.ajax({
    url: '/home/ajax', 
    cache: false,
    success: function (result) {
        $('#result').append($('<div/>').html(
            result.startTime + ' | ' + result.endTime
        ));
    }
});
Run Code Online (Sandbox Code Playgroud)