以前發佈了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】