在前后端进行数据传输时,有时需要传输大文件。WebUploader提供了一些前端传输图片和文件等地方法。但是,当上传文件较大时,会被服务器端限制,阻止其上传。
在ASP.Net中,调整服务器接受文件的大小的配置方法如下:
<httpRuntime executionTimeout="90" maxRequestLength="40960" useFullyQualifiedRedirectUrl="false"minFreeThreads="8" minLocalRequestFreeThreads="4" appRequestQueueLimit="100" enableVersionHeader="false"/>
每个参数的作用为:
executionTimeout:表示允许执行请求的最大时间限制,单位为秒 。
maxRequestLength:指示 ASP.NET支持的最大文件上载大小。该限制可用于防止因用户将大量文件传递到该服务器而导致的拒绝服务攻击。指定的大小以 KB 为单位。默认值为 4096KB (4 MB)。
useFullyQualifiedRedirectUrl:表示指示客户端重定向是否是完全限定的(采用”http://server/path” 格式,这是某些移动控件所必需的),或者指示是否代之以将相对重定向发送到客户端。如果为True,则所有不是完全限定的重定向都将自动转换为完全限定的格式。false 是默认选项。
minFreeThreads:表示指定允许执行新请求的自由线程的最小数目。ASP.NET为要求附加线程来完成其处理的请求而使指定数目的线程保持自由状态。默认值为 8。
minLocalRequestFreeThreads:表示ASP.NET保持的允许执行新本地请求的自由线程的最小数目。该线程数目是为从本地主机传入的请求而保留的,以防某些请求在其处理期间发出对本地主机的子请求。这避免了可能的因递归重新进入Web 服务器而导致的死锁。
appRequestQueueLimit:表示ASP.NET将为应用程序排队的请求的最大数目。当没有足够的自由线程来处理请求时,将对请求进行排队。当队列超出了该设置中指定的限制时,将通过“503 -服务器太忙”错误信息拒绝传入的请求。 enableVersionHeader:表示指定 ASP.NET是否应输出版本标头。Microsoft Visual Studio 2005 使用该属性来确定当前使用的 ASP.NET版本。对于生产环境,该属性不是必需的,可以禁用。
但是,当文件过大时会即使Web允许通过,IIS也会拒绝传输,这时,就需要使用分片上传。
分片上传是指将想要上传的文件在前端切割成很小的一片,依次传给服务器,再在服务器端将文件组合成完整的文件。 javascript自身提供了上传文件的方法,也提供了上传文件的一种对象方法FormData。可以看JS+WebService 大文件分片上传代码及解析这篇文章地JS部分。
Web Uploader封装好了上传的方法,可以直接使用。
html部分
<div id="uploaderrecovery" class="wu-example">
<div id="thelistrecovery" class="uploader-list"></div>
<div class="btns">
<div id="pickerrecovery">选择文件</div>
<button id="ctlBtnrecovery" class="btn btn-default">开始上传</button>
</div>
</div>
还要记得引用Web Uploader文件
javascript部分
if (recoveryindex === 0) {
Recovery();
}
var recoveryindex = 0; //全局变量,判断uploader实例化次数,注意只能实例化一次
function Recovery() {
recoveryindex = 1;
var GUID = WebUploader.Base.guid(); //当前页面是生成的GUID作为标示
var $list = $("#thelistrecovery");
var uploader = WebUploader.create({
// swf文件路径
swf: 'Libs/webuploader/0.1.5/Uploader.swf',
// 文件接收服务端。
server: WebBuckupAddress, //C#地址:http://localhost:7792/Backup.asmx/backuprecovery
// 选择文件的按钮。可选。
// 内部根据当前运行是创建,可能是input元素,也可能是flash.
pick: '#pickerrecovery',
formData: { guid: GUID },
// 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
resize: false,
chunked:true,
threads: 1,
accept: { //指定格式为zip
title: 'File',
extensions: 'zip',
mimeTypes: 'application/zip'}
})
// 当有文件被添加进队列的时候
uploader.on( 'fileQueued', function( file ) {
$list.append('<div id="' + file.id + '" class="item">' +
'<h4 id="recoveryinfo" class="info">' + file.name + '</h4>' +
'<p class="state">等待上传...</p>' +
'</div>');
});
uploader.on( 'beforeFileQueued', function( file ) {
$list.empty();
uploader.reset();
uploader.reset();
});
// 文件上传过程中创建进度条实时显示。
uploader.on( 'uploadProgress', function( file, percentage ) {
var $li = $( '#'+file.id ),
$percent = $li.find('.progress .progress-bar');
// 避免重复创建
if ( !$percent.length ) {
$percent = $('<div class="progress progress-striped active">' +
'<div class="progress-bar" role="progressbar" style="width: 0%">' +
'</div>' +
'</div>').appendTo( $li ).find('.progress-bar');
}
$li.find('p.state').text('上传中');
$percent.css( 'width', percentage * 100 + '%' );
});
uploader.on( 'uploadSuccess', function( file ) {
$( '#'+file.id ).find('p.state').text('已上传');
});
uploader.on( 'uploadError', function( file ,code) {
$( '#'+file.id ).find('p.state').text('上传出错');
alert(code);
});
uploader.on( 'uploadComplete', function( file ) {
$( '#'+file.id ).find('.progress').fadeOut();
});
uploader.on( 'uploadAccept', function( file, response ) {
if ( response['hasError']!=false ) {
// 通过return false来告诉组件,此文件上传有错。
return false;
}
else
{
return true;
}
});
$("#ctlBtnrecovery").on('click', function () {
uploader.upload();
});
}
C#部分
Web.config文件
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<!--这部分为添加的配置跨域-->
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Methods" value="OPTIONS,POST,GET"/>
<add name="Access-Control-Allow-Headers" value="x-requested-with,content-type"/>
<add name="Access-Control-Allow-Origin" value="*"/>
</customHeaders>
</httpProtocol>
</configuration>
WebService.asmx文件
[WebMethod]
public void backuprecovery()
{
BackupRecovery br = new BackupRecovery();
br.Recovery();
}
以下函数都在BackupRecovery这个class中
来自用webuploader分片上传大文件没你想象的难
public void Recovery()
{
HttpContext context = System.Web.HttpContext.Current;
context.Response.ContentType = "text/plain";
context.Response.Write("{\"chunked\" : true, \"hasError\" : false}");
//如果进行了分片
if (context.Request.Form.AllKeys.Any(m => m == "chunk"))
{
//取得chunk和chunks
int chunk = Convert.ToInt32(context.Request.Form["chunk"]);//当前分片在上传分片中的顺序(从0开始)
int chunks = Convert.ToInt32(context.Request.Form["chunks"]);//总分片数
//根据GUID创建用该GUID命名的临时文件夹
//string folder = context.Server.MapPath("~/1/" + context.Request["guid"] + "/");
string folder = backuprecovery + context.Request["guid"] + "/"; //文件存放绝对路径由写好地backuprecovery 和前端设定好的guid决定
string path = folder + chunk;
//建立临时传输文件夹
if (!Directory.Exists(Path.GetDirectoryName(folder)))
{
Directory.CreateDirectory(folder);
}
FileStream addFile = new FileStream(path, FileMode.Append, FileAccess.Write);
BinaryWriter AddWriter = new BinaryWriter(addFile);
//获得上传的分片数据流
HttpPostedFile file = context.Request.Files[0];
Stream stream = file.InputStream;
BinaryReader TempReader = new BinaryReader(stream);
//将上传的分片追加到临时文件末尾
AddWriter.Write(TempReader.ReadBytes((int)stream.Length));
//关闭BinaryReader文件阅读器
TempReader.Close();
stream.Close();
AddWriter.Close();
addFile.Close();
TempReader.Dispose();
stream.Dispose();
AddWriter.Dispose();
addFile.Dispose();
if (chunk == chunks - 1)
{
ProcessRequest(context.Request["guid"], Path.GetExtension(file.FileName));
}
}
else//没有分片直接保存
{
DeleteFolder(backuprecoveryfile);
string targetPath = backuprecovery + "data" + Path.GetExtension(context.Request.Files[0].FileName); //data为指定zip的名字
context.Request.Files[0].SaveAs(targetPath);
}
}
private void ProcessRequest(string guid, string fileExt)
{
HttpContext context = System.Web.HttpContext.Current;
context.Response.ContentType = "text/plain";
string sourcePath = Path.Combine(backuprecovery, guid + "/");//源数据文件夹
string targetPath = Path.Combine(backuprecovery, Guid.NewGuid() + fileExt);//合并后的文件
DirectoryInfo dicInfo = new DirectoryInfo(sourcePath);
if (Directory.Exists(Path.GetDirectoryName(sourcePath)))
{
FileInfo[] files = dicInfo.GetFiles();
foreach (FileInfo file in files.OrderBy(f => int.Parse(f.Name)))
{
FileStream addFile = new FileStream(targetPath, FileMode.Append, FileAccess.Write);
BinaryWriter AddWriter = new BinaryWriter(addFile);
//获得上传的分片数据流
Stream stream = file.Open(FileMode.Open);
BinaryReader TempReader = new BinaryReader(stream);
//将上传的分片追加到临时文件末尾
AddWriter.Write(TempReader.ReadBytes((int)stream.Length));
//关闭BinaryReader文件阅读器
TempReader.Close();
stream.Close();
AddWriter.Close();
addFile.Close();
TempReader.Dispose();
stream.Dispose();
AddWriter.Dispose();
addFile.Dispose();
}
DeleteFolder(sourcePath);
}
}
/// <summary>
/// 删除文件夹
/// </summary>
/// <param name="strPath"></param>
private static void DeleteFolder(string strPath)
{
if (strPath != backuprecoveryfile)
{
Directory.Delete(strPath, true);
}
else
{
if (Directory.GetDirectories(strPath).Length > 0)
{
foreach (string fl in Directory.GetDirectories(strPath))
{
Directory.Delete(fl, true);
}
}
//删除这个目录下的所有文件
if (Directory.GetFiles(strPath).Length > 0)
{
foreach (string f in Directory.GetFiles(strPath))
{
System.IO.File.Delete(f);
}
}
}
}