以前发布了ajax的通用解决方案,核心的ajax发布请求,以及集成了轮询。此次去外国网站逛逛,而后发现了ajax level2的上传文件,因此就有了把ajax的上传文件集成进去的想法,ajax方案的level2的改进就不介绍了,不清楚的可到前几篇博客去看看。咱们直接切入主题。javascript
概念介绍:html
1. js的FormData:js中在新的版本中已经支持了FormData对象,能够初始化一个空的form,或者初始化已经存在的form,浏览器测试代码。前端
2. 浏览器的支持:浏览器已支持input=file的时候查看文件,具体包括文件的大小(size)和类型(type),浏览器测试以下html5
3. xmlhttprequest:支持发送(send方法)新的数据类型,包括DOMString
、Document
、FormData
、Blob
、File
、ArrayBuffer。具体参见ajax设计方案的规范
java
工具准备:nginx
1. 前端代码git
2. nginx服务器(分离)github
3. IIS服务器(部署后台)web
4. 后台代码(webAPI)ajax
什么很少说,先贴代码:
前端代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
/*
* ajax上传文件
* url 文件上传地址
* fileSelector input=file 选择器(支持多文件上传,只要后台接口支持)
* size 文件限制大小
* fileType 文件限制类型 mime类型
* success 上传成功处理
* error 上传失败处理
* timeout 超时处理
*
* return: status: 0 请选择文件
* 1 超出文件限制大小
* 2 非容许文件格式
* */
upload:
function
(url,fileSelector,size,fileType,success,error,timeout){
var
formdata =
new
FormData(),fileNode = document.querySelector(fileSelector),fileCount = fileNode.files.length,data={},result ={};
//如下为上传文件限制检查
if
( fileCount > 0 ){
tool.each(Array.prototype.slice.call(fileNode.files),
function
(value){
//检查文件大小
if
(value.size > size){
result[
"status"
] = 1;
result[
"errMsg"
] =
"超出文件限制大小"
;
}
else
{
//检查文件格式.由于支持formdata,天然支持数组的indexof(h5)
if
(fileType.indexOf(value.type)=== -1 ){
result[
"status"
] = 2;
result[
"errMsg"
] =
"非容许文件格式"
;
}
else
{
formdata.append(value.name,value);
};
};
});
}
else
{
result[
"status"
] = 0;
result[
"errMsg"
] =
"请选择文件"
;
};
if
(result.status !== undefined)
return
result;
//若是有错误信息直接抛出去,结束运行
var
ajaxParam ={
type:
"post"
,
url:url,
data:formdata,
isFormData:
true
,
success:success,
error:error,
timeout:timeout
};
ajax.common(ajaxParam);
},
};
|
后端接口代码(C#的webAPI),代码比较简陋,能完成测试就好
[Route("upload3")] public async Task<HttpResponseMessage> PostFormData() { // Check if the request contains multipart/form-data. // 检查该请求是否含有multipart/form-data if (!Request.Content.IsMimeMultipartContent()) { throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } string root = HttpContext.Current.Server.MapPath("~/uploadfile"); var provider = new ReNameMultipartFormDataStreamProvider(root); try { // Read the form data. // 读取表单数据 var task = await Request.Content.ReadAsMultipartAsync(provider).ContinueWith(t => { if (t.IsFaulted || t.IsCanceled) { Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception); } string fileName = string.Empty; foreach (MultipartFileData file in provider.FileData) { fileName = file.LocalFileName; } //返回上传后的文件全路径 return new HttpResponseMessage() { Content = new StringContent(fileName) }; }); return Request.CreateResponse(HttpStatusCode.OK); } catch (System.Exception e) { return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e); } } /// /// 重命名上传的文件 /// public class ReNameMultipartFormDataStreamProvider : MultipartFormDataStreamProvider { public ReNameMultipartFormDataStreamProvider(string root) : base(root) { } public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers) { //截取文件扩展名 string exp = Path.GetExtension(headers.ContentDisposition.FileName.TrimStart('"').TrimEnd('"')); string name = base.GetLocalFileName(headers); return name + exp; } }
浏览器测试结果(几乎全部主流浏览器都支持,除了IE10如下)
测试代码以下:
1
2
3
4
5
6
7
8
9
|
var
temp = ajax.upload(
"/api/ajaxUpload/upload3/"
,
"#file1"
, 1024 * 1024 * 1, [
"image/png"
,
"image/bmp"
],
function
(data) {
if
(data ==
"true"
) {
alert(
"上传成功!"
);
}
if
(data ==
"error"
) {
alert(data);
}
});
console.log(temp);
|
格式限制测试结果以下
1. 选取超过限制大小的文件
2. 选取非容许格式的文件
3. 未选择上传文件
文件上传成功测试
IE十、11
safari
火狐
谷歌
opera
edge
360浏览器
下面扯一下遇到的问题
问题一 IE8-9兼容问题
在兼容性网站(http://caniuse.com/)查询兼容性,ajax leve2支持IE10+版本,因此若是在IE8-9上使用纯前端代码进行上传文件的话,只有传统的form标签
html代码以下:
1
2
3
4
5
6
|
<form id=
"formUpload"
action=
"/api/ajaxUpload/upload2/"
method=
"post"
enctype=
"multipart/form-data"
target=
"framFile"
>
<input name=
"isIE8"
type=
"text"
value=
"1"
readonly style=
"display: none"
/>
<input id=
"iefile"
type=
"file"
name=
"age"
/>
<input type=
"submit"
value=
"submit"
>
</form>
<iframe id=
"framFile"
name=
"framFile"
src=
"postMsg.html"
></iframe>
|
缺点:
1. 每次form提交的时候都会刷新页面,若是想作异步无刷新,用iframe作提交页面
2. IE8-9没法在前端对文件进行大小和类型检查(使用IE的文件组件不安全,由于能够修改系统上全部文件,容易被攻击,并且浏览器都是默认关闭的)
3. 上传文件接口不能有返回值,不然在IE8下会将接口返回值做为文件下载下来,且没法取得返回值(用了N种方法),可是在其余浏览器中ajax的成功事件会去作判断,测试图片以下
一些建议:若是真的要作IE8-9,如今广泛的方案是将flash插件和ajax Level2的上传进行组合,支持H5的用ajax上传,不支持初始化flash上传插件。
PS:对于那些偏执的,必定要在IE8-9用纯前端代码支持上传的,还有一种折中的方案,和这种思想相似,可是我作了优化,思路以下:
须要2个接口:上传文件接口,IE8-9下上传结果查询接口
a. 首先使用form的无刷新上传(ifarme)
b. 后台接收到formdata数据判断是不是IE8-9的上传,是的话将该用户上传文件是否成功的状态改变(无论存库或者其余地方),不然直接返回上传结果
c. 前端在form的submit以后,发起获得一次结果的轮询,若是获得结果,则直接结束轮询,结果查询接口也将该用户的上传文件状态清空
问题二 通常ajax请求和formdata请求,后台取值问题。
传统http请求,能够直接在接口参数中取得数据,可是使用formdata进行ajax请求的话,后台接口须要从formdata对象中取数据,包括文件啥的。由于这个我写后台接口的时候就懵逼了好长一段时间,而后左查查右查查,终于明白取值方式也不同了。
问题三 关于formdata上传文件,具体能上传多大文件的限制问题
上传文件的限制取决于web容器可接受上传文件的大小,tomcat、IIS等web容器都有本身的设置方法,具体可搜索引擎,你懂的
问题四 前端对大文件的传输解决方案,具体可参考该文章
在新的版本中,就是支持H5的版本中,有了File对象能够切割文件,由于在取到input=file中取到的文件都是File类型,File对象有个方法slice,能够切割文件,而后分配一个xhr上传。主要是后台的切割文件重组问题不是很清楚,因此我暂时也没有集成大文件上传方法。
代码已集成github:https://github.com/GerryIsWarrior/ajax 点颗星星是我最大的鼓励,有什么问题能够博客、邮箱、github上留言
这一次上传版本,代码作过变更,变更以下:
个人全栈书签,此次更新整理了国内顶级互联网和著名的一些互联网公司的招聘网站,但愿你们找到好工做,^_^
github地址:https://github.com/GerryIsWarrior/MyBookmarks
【转发自http://www.cnblogs.com/GerryOfZhong/p/6274536.html】