Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/450.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 并行文件上传XMLHttpRequest请求以及它们获胜的原因';行不通_Javascript_Ajax_Browser_Asp.net Mvc 5_Xmlhttprequest - Fatal编程技术网

Javascript 并行文件上传XMLHttpRequest请求以及它们获胜的原因';行不通

Javascript 并行文件上传XMLHttpRequest请求以及它们获胜的原因';行不通,javascript,ajax,browser,asp.net-mvc-5,xmlhttprequest,Javascript,Ajax,Browser,Asp.net Mvc 5,Xmlhttprequest,我正在尝试使用XMLHttpRequest并行上传许多(目前为3个)文件。如果我有一些代码,从许多删除的文件列表中提取它们,并确保在每一时刻我发送3个文件(如果可用) 这是我的代码,据我所知是标准的: var xhr = item._xhr = new XMLHttpRequest(); var form = new FormData(); var that = this; angular.forE

我正在尝试使用XMLHttpRequest并行上传许多(目前为3个)文件。如果我有一些代码,从许多删除的文件列表中提取它们,并确保在每一时刻我发送3个文件(如果可用)

这是我的代码,据我所知是标准的:

            var xhr = item._xhr = new XMLHttpRequest();
            var form = new FormData();
            var that = this;

            angular.forEach(item.formData, function(obj) {
                angular.forEach(obj, function(value, key) {
                    form.append(key, value);
                });
            });

            form.append(item.alias, item._file, item.file.name);

            xhr.upload.onprogress = function(event) {
                // ...
            };

            xhr.onload = function() {
                // ...
            };

            xhr.onerror = function() {
                // ...
            };

            xhr.onabort = function() {
                // ...
            };

            xhr.open(item.method, item.url, true);

            xhr.withCredentials = item.withCredentials;

            angular.forEach(item.headers, function(value, name) {
                xhr.setRequestHeader(name, value);
            });

            xhr.send(form);
查看Opera的开发者工具中的网络监视器,我发现这一点很有效,并且我始终得到3个“正在处理”的文件:

但是,如果我查看请求的进展情况,我会看到3个上载中的2个(这里是看起来运行时间很长的上载)处于“挂起”状态,并且每次只有3个请求中的1个真正处于活动状态。这也反映在上传时间上,因为由于这种并行性,时间似乎没有改善

我把控制台日志放在了我的代码中,这似乎不是我代码的问题


我应该知道,在并行上传文件时是否存在浏览器限制?据我所知,AJAX在请求数量上的限制比我在这里使用的要高。。。向请求中添加文件是否会改变情况?

HTTP/1.1 RFC

HTTP/1.1 RFC的第8.1.4节说,“单用户客户端与任何服务器或代理的连接不应超过2个


请在此处阅读更多信息:

这是ASP.NET导致的问题。 来自同一SessionId的多个请求被序列化,因为它们锁定了会话对象

我的解决办法是使会话对此特定操作为只读。这样,就不需要锁定。 这是我的代码(原始代码取自):

公共类CustomControllerFactory:DefaultControllerFactory
{
受保护的重写会话状态行为GetControllerSessionBehavior(RequestContext RequestContext,类型controllerType)
{
如果(controllerType==null)
{
返回SessionStateBehavior.Default;
}
var actionName=requestContext.RouteData.Values[“action”].ToString();
方法信息操作方法信息;
var methods=controllerType.GetMethods(BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);

actionMethodInfo=methods.FirstOrDefault(x=>x.Name==actionName&&x.GetCustomAttribute

似乎是服务器端的一个错误。浏览器端没有问题。浏览器已经为3个请求同时请求了握手。您的服务器一次可能只能处理1个请求。这就是握手长时间处于挂起状态的原因。您需要增加e您的服务器能够处理的请求数。@yeshashah我的服务器是ISS,没有设置限制。我的框架是ASP.NET,在我的代码中没有任何地方可以锁定/阻止内容。但是,在您的评论和一些搜索之后,我偶然发现了这一点,很可能是这样:。如果这是真的,我必须找到一种方法来绕过它havior…是的。许多服务器避免同时处理具有相同sessionId的请求,以避免写入操作时出现争用情况。AWS S3允许直接浏览器上载,其中文件分为单独的块,每个块同时发送到服务器,然后服务器按照fileId和chunkId的正确顺序进行组装。您可以探索类似的东西。@yeshashah但使用块有什么帮助?这最终不会有同样的问题吗?同样,这将是多个请求争夺同一个资源(在我的例子中是用户会话对象)。当然锁定时间会更小,但这些锁定时间的总和仍然是相同的(或多或少)作为完成文件上载所用的时间。我很惊讶这会缩短上载时间。我为ASP服务器找到的一个解决方案是禁用会话状态:
设置EnableSessionState=“ReadOnly”将阻止该页面获得会话状态的独占锁(但页面本身必须等待用户的其他非只读请求完成后才能加载)。
不确定这样做的效果如何。下一句话是:“这里的关键是“应该”。Web客户端不必遵循此准则。”并行连接是一种非常简洁的技术,在很多地方都可以使用它进行优化,比如AWS S2浏览器上载,方法是将文件块同时发送到服务器,并在服务器上进行组装,以加快上载速度。与服务器或代理建立1个以上的连接没有什么错。
public class CustomControllerFactory : DefaultControllerFactory
{
    protected override SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            return SessionStateBehavior.Default;
        }

        var actionName = requestContext.RouteData.Values["action"].ToString();
        MethodInfo actionMethodInfo;
        var methods = controllerType.GetMethods(BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
        actionMethodInfo = methods.FirstOrDefault(x => x.Name == actionName && x.GetCustomAttribute<ActionSessionStateAttribute>() != null);
        if (actionMethodInfo != null)
        {
            var actionSessionStateAttr = actionMethodInfo.GetCustomAttributes(typeof(ActionSessionStateAttribute), false)
                .OfType<ActionSessionStateAttribute>()
                .FirstOrDefault();

            if (actionSessionStateAttr != null)
            {
                return actionSessionStateAttr.Behavior;
            }
        }
        return base.GetControllerSessionBehavior(requestContext, controllerType);
    }
}


[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class ActionSessionStateAttribute : Attribute
{
    public SessionStateBehavior Behavior { get; private set; }
    public ActionSessionStateAttribute(SessionStateBehavior behavior)
    {
        this.Behavior = behavior;
    }
}

// In your Global.asax.cs
protected void Application_Start(object sender, EventArgs e)
{
    // .........
    ControllerBuilder.Current.SetControllerFactory(typeof(CustomControllerFactory));
}


// You use it on the controller action like that:
[HttpPost]
[Authorize(Roles = "Administrators")]
[ValidateAntiForgeryToken]
[ActionSessionState(SessionStateBehavior.ReadOnly)]
public async Task<ActionResult> AngularUpload(HttpPostedFileBase file){}