Javascript 并行文件上传XMLHttpRequest请求以及它们获胜的原因';行不通
我正在尝试使用XMLHttpRequest并行上传许多(目前为3个)文件。如果我有一些代码,从许多删除的文件列表中提取它们,并确保在每一时刻我发送3个文件(如果可用) 这是我的代码,据我所知是标准的: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
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){}