javascript - 并行文件上传 XMLHttpRequest 请求以及为什么它们不起作用
问题描述
我正在尝试使用 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 限制的请求数量比我在这里使用的要高得多……向请求中添加文件是否会改变事情?
解决方案
原来是 ASP.NET 导致了这个问题。来自同一个 SessionId 的多个请求会被序列化,因为它们会锁定会话对象。
见这里。
我的解决方法是让会话对于这个特定的操作是只读的。这样,就不需要锁定。这是我的代码(取自这里的原始代码):
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){}
推荐阅读
- java - Java getter setter 无法存储值
- amazon-cloudfront - 使用 aws cli 在 extsting 云端分发中添加额外的来源和行为
- mongodb - 快速查询MongoDB的数据结构设计
- swift - 任何人都可以帮助我如何从给定的示例中获得价值,因为我是 swift 新手
- python - pygame屏幕自动翻倍
- python - 如何在熊猫中没有 to_datetime 函数的列中格式化日期时间值?
- asp.net-mvc - 如何将用户信息返回给 View ASP.net MVC
- r - 如何用条件索引分隔每日数据(增加、减少、增长)?
- c# - 如何以编程方式加快系统时间?
- facebook - 通过 Facebook 图形 API 在 Facebook 的时间线中发布上传