JS&ASPDotNet_大文件上传问题
JS&ASPDotNet_大文件上传问题
1.ASP.NET默认能够上传文件的大小限制为:2MB;
2.大文件上传的限制因素有:
1) Request请求大小限制;
2) Request请求超时时间限制:当上传大文件或网速较差时,上传时间突破单次会话时长限制
3)内存大小限制:前台和后台机器在碰到超大文件时单次处理均会面临内存不足的危险;
3.大文件上传的解决方案有:
1)各种文件上传插件:如BootStrap下的fileInput.js,但经试验存在问题,当上传超过1.5G文件时报编码错误或其他各种Bug,网上所说的通过改写fileInput.js源文件默认文件大小限制
无效;
2)最根本的解决方案:前端分块,后端拼接,从根本上规避文件大小限制和机器内存不足的风险;会话时长应该设置成满足整个上传过程的时间需求;
4.WebConfigx设置示例:
4.1 设置请求大小(B)、请求超时时间(s)
<system.web>
<httpRuntime targetFramework="4.5" maxRequestLength="900000000" executionTimeout="3600" />
</system.web>
4.2 设置允许的最大内容长度
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="900000000"></requestLimits>
</requestFiltering>
</security>
</system.webServer>
5.自定义文件上传类(需后端配合):
特点:
支持任意大小文件上传(原理:前端分块,后端拼接);
支持进度条;
可取消;
支持取消、失败和上传成功事件回调
5.1 UploadFileHelper类定义
//#region UploadFileHelper类定义
function UploadFileHelper(url, flag, fileData, size_chunck, onUploadCompleted,onUploadFailed,onUploadCanceled)
{
this.Url = url;//处理程序地址
this.Flag = flag; //可选的处理方法选择符
this.FileData = fileData;//文件数据;
//分块大小
if (size_chunck == undefined || size_chunck == null)
UploadFileHelper.prototype.Size_chunk = 10 * 1024 * 1024;//默认分块大小10MB,单位字节
else
UploadFileHelper.prototype.Size_chunk = size_chunck;
//注册成功、失败、取消回调事件
if (typeof onUploadCompleted == "function")
ploadFileHelper.prototype.OnUploadCompleted = onUploadCompleted;
else
ploadFileHelper.prototype.OnUploadCompleted = null;
if (typeof onUploadFailed == "function")
ploadFileHelper.prototype.OnUploadFailed = onUploadFailed;
else
ploadFileHelper.prototype.OnUploadFailed = null;
if (typeof onUploadCanceled == "function")
ploadFileHelper.prototype.OnUploadCanceled = onUploadCanceled;
else
ploadFileHelper.prototype.OnUploadCanceled = null;
UploadFileHelper.prototype.Cancel = false;//重置取消任务命令
UploadFileHelper.prototype.JQuerytObj_ParentProgressBar = null;
UploadFileHelper.prototype.JQuerytObj_ProgressBarValue = null;
UploadFileHelper.prototype.JQueryObj_PercentText = null;
}
UploadFileHelper.prototype =
{
constructor: UploadFileHelper,
Size_chunk: 10 * 1024 * 1024,//默认分块大小10MB,单位字节
Cancel: false,//任取取消标记
OnUploadCanceled: null,
OnUploadCompleted: null,
OnUploadFailed: null,
JQuerytObj_ParentProgressBar: null,//用于显示进度条总值的JQuery对象
JQuerytObj_ProgressBarValue: null,//用于显示进度条Value的JQuery对象
JQueryObj_PercentText: null,//进度文本
UploadFile: function ()
{
//#region step1: 参数检查
if (this.FileData == undefined || this.FileData == null)
{
alert("参数错误:无效文件!");
return false;
}
if (this.Url == undefined || this.Url == null || this.Url == '')
{
alert("参数错误:服务器地址错误!");
return false;
}
//#endregion
//#region step2: 绑定xmlHtppRequest状态监听函数
var xhr = new XMLHttpRequest(); xhr.upload.onprogress = function (e) { };
xhr.upload.onprogress = function (e) { };
var xhrOnProgress = function (fun)
{
xhrOnProgress.onprogress = fun; //绑定监听
//使用闭包实现监听绑
return function ()
{
//通过$.ajaxSettings.xhr();获得XMLHttpRequest对象
var xhr = $.ajaxSettings.xhr();
//判断监听函数是否为函数
if (typeof xhrOnProgress.onprogress !== 'function')
return xhr;
//如果有监听函数并且xhr对象支持绑定时就把监听函数绑定上去
if (xhrOnProgress.onprogress && xhr.upload)
{
xhr.upload.onprogress = xhrOnProgress.onprogress;
}
return xhr;
}
}
//#endregion
//#region step3: 分块线性递归上传
var size_file = this.FileData.size;//记录文件总大小(B)
var size_chunk = 10 * 1024 * 1024;//分块大小10MB,单位字节
var count_chunck = Math.ceil(size_file / size_chunk);//文件块数
var count_haveUploaded = 0;//已经上传的文件块数
//设置服务器端临时文件名
var tempFileNameOnServer = this.FileData.name + "#" + this.getGUID();
var upload = function (index, file, url, flag)
{
var size_realChunck;
var file_chunck;
var formData;
if (size_file > size_chunk)//需要分块上传
{
var size_left = size_file - size_chunk * index;//剩下的文件大小
if (size_left > 0)
{
size_realChunck = Math.min(size_chunk, size_left);//真实块大小
file_chunck = file.slice(index * size_chunk, index * size_chunk + size_realChunck);//截取 部分文件 块
formData = new FormData();
formData.append("file", file_chunck);
formData.append("fileName", tempFileNameOnServer);//向后台传输每个分块所属的文件名
if (flag != null && flag != undefined)
formData.append("flag", flag);
if (UploadFileHelper.prototype.Cancel == true)
formData.append("controlSignal", "cancel");
$.ajax({
url: url,
type: "POST",
data: formData,
processData: false, // 告诉jQuery不要去处理发送的数据
contentType: false, // 告诉jQuery不要去设置Content-Type请求头
success: function (data, status)
{
if (data == "正在上传")
{
//刷新进度
if (UploadFileHelper.prototype.JQuerytObj_ParentProgressBar != null &&
UploadFileHelper.prototype.JQuerytObj_ProgressBarValue != null)
{
++count_haveUploaded;
var percent = (count_haveUploaded / count_chunck);
//获取进度条总长度
var width_parent = UploadFileHelper.prototype.JQuerytObj_ParentProgressBar.css("width");
width_parent = width_parent.toString().replace("px", "");
//设置value值
var width_value = parseFloat(width_parent) * percent;
UploadFileHelper.prototype.JQuerytObj_ProgressBarValue.css("width", width_value);
//设置进度文本
if (UploadFileHelper.prototype.JQueryObj_PercentText != null)
{
var percentText = (percent * 100).toFixed(2).toString() + "%";
UploadFileHelper.prototype.JQueryObj_PercentText.html(percentText);
}
}
//递归调用上传文件
upload(++index, file, url, tempFileNameOnServer, flag);
}
else if (data == "取消成功")
{
//alert("成功取消上传");
if (UploadFileHelper.prototype.OnUploadCanceled != null)
{
UploadFileHelper.prototype.OnUploadCanceled();
}
}
else
{
alert(data);
return false;
}
},
error: function (data, status)
{
alert('文件上传失败:' + status);
return false;
}
});
}
else
{
//通知后台文件上传结束
var parameter = { controlSignal: "uploadCompleted", fileName: tempFileNameOnServer };
$.post(url, parameter, function (data, status)
{
if (status == "success")
{
//alert(data);
if (data == "上传成功" && UploadFileHelper.prototype.OnUploadCompleted != null)
{
UploadFileHelper.prototype.OnUploadCompleted();
}
}
else
{
alert("文件上传结束,但向后台发送通知时失败!");
}
});
return true;
}
}
else //无需分块上传
{
formData = new FormData();
formData.append("file", file);
formData.append("fileName", tempFileNameOnServer);//向后台传输每个分块所属的文件名
if (flag != null && flag != undefined)
formData.append("flag", flag);
$.ajax({
url: url,
type: "POST",
data: formData,
processData: false, // 告诉jQuery不要去处理发送的数据
contentType: false, // 告诉jQuery不要去设置Content-Type请求头
success: function (data, status)
{
if (data == "正在上传")//小文件一次上传完成后台返回的信息和分块上传一样都是正在上传
{
//通知后台文件上传结束
var parameter = { controlSignal: "uploadCompleted", fileName: tempFileNameOnServer };
$.post(url, parameter, function (data, status)
{
if (status == "success")
{
//alert(data);
if (data == "上传成功" && UploadFileHelper.prototype.OnUploadCompleted != null)
{
UploadFileHelper.prototype.OnUploadCompleted();
}
}
else
{
alert("文件上传结束,但向后台发送通知时失败!");
}
});
}
else if (data == "取消成功")
{
//小文件无法取消
alert("成功取消上传");
}
else
{
alert(data);
}
},
error: function (data, status)
{
alert('文件上传失败:' + status);
return false;
},
xhr: xhrOnProgress(function (e)
{
if (UploadFileHelper.prototype.JQuerytObj_ParentProgressBar != null &&
UploadFileHelper.prototype.JQuerytObj_ProgressBarValue != null)
{
var percent = (e.loaded / size_file);
if (percent > 1)
percent = 1.0000;
//获取进度条总长度
var width_parent = UploadFileHelper.prototype.JQuerytObj_ParentProgressBar.css("width");
width_parent = width_parent.toString().replace("px", "");
//设置value值
var width_value = parseFloat(width_parent) * percent;
UploadFileHelper.prototype.JQuerytObj_ProgressBarValue.css("width", width_value);
//设置进度文本
if (UploadFileHelper.prototype.JQueryObj_PercentText != null)
{
var percentText = (percent * 100).toFixed(2).toString() + "%";
UploadFileHelper.prototype.JQueryObj_PercentText.html(percentText);
}
}
}),
});
}
}
upload(0, this.FileData, this.Url, this.Flag);
//#endregion
},
getGUID: function getGUID()
{
function S4()
{
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}
return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
}
};
//#endregion
5.2 后台示例
//ASP.NET代码:
protected void Page_Load(object sender, EventArgs e)
{
string info = "正在上传";
string fileName_withGUID = Request.Form["fileName"];
string path_store = Server.MapPath("~/Resources/");
string fileName_withGUID_fullPath = Path.Combine(path_store, fileName_withGUID);
string controlSignal = Request.Form["controlSignal"]; //前台回传的kon信号
if (controlSignal == "uploadCompleted")
{
#region 上传结束
//重设文件名
try
{
FileInfo fi = new FileInfo(fileName_withGUID_fullPath);
//获取扩展名
int startIndex=fileName_withGUID_fullPath.IndexOf('.');
int endIndex=fileName_withGUID_fullPath.IndexOf('#');
string fileExtension = fileName_withGUID_fullPath.Substring(startIndex, endIndex - startIndex);
string[] fileName_arr=fileName_withGUID_fullPath.Split('.');
string newSafeFileName =string.Format("{0}_{1}{2}",fileName_arr[0],Guid.NewGuid().ToString(),fileExtension);
string newFileName = Path.Combine(Directory.GetParent(fileName_withGUID_fullPath).ToString(), newSafeFileName).ToString();
fi.MoveTo(newFileName);
info = "上传成功";
}
catch (Exception ex)
{
info = "重命名文件失败";
}
#endregion
}
else if (controlSignal == "cancel")
{
#region 取消上传
//删除已上传的文件
try
{
File.Delete(fileName_withGUID_fullPath);
info = "取消成功";
}
catch (Exception ex)
{
info = string.Format("文件删除失败");
}
#endregion
}
else
{
#region 上传中
try
{
using (FileStream fs = new FileStream(fileName_withGUID_fullPath, FileMode.Append, FileAccess.Write))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
BinaryReader br = new BinaryReader(Request.Files[0].InputStream);
byte[] bytes = br.ReadBytes((int)Request.Files[0].InputStream.Length);
bw.Write(bytes);
}
}
}
catch (Exception ex)
{
info = "上传失败:" + ex.Message;
}
#endregion
}
Response.Write(info);
}
5.3 调用示例
var uploafHelper = new UploadFileHelper();
uploafHelper.FileData = file;
uploafHelper.Url = url;
uploafHelper.Flag = "";
UploadFileHelper.prototype.OnUploadCompleted = function () { alert("上传成功AAAAA") };
UploadFileHelper.prototype.OnUploadCanceled = function () { alert("取消上传AAAAA") };
UploadFileHelper.prototype.JQuerytObj_ParentProgressBar = $("#div_parentProgressBar");
UploadFileHelper.prototype.JQuerytObj_ProgressBarValue = $("#div_sonProgressBar");
UploadFileHelper.prototype.JQueryObj_PercentText = $("#progressInfoText");
uploafHelper.UploadFile();

浙公网安备 33010602011771号