在此以前讓我感慨一下如今的前端開發的氛圍。我遇到好多人,給個人觀念都是,這個東西這個框架有了,那個東西那個框架作了,前端嘛,學幾個框架,這個拼湊一下那個拼湊一下就行了。其實我想問,東西都框架作了,那你會什麼?會吹牛逼?會撕逼?javascript
我在簡歷上寫專一原聲js,曾經被幾我的笑過。我一直搞不懂,框架會過期,基礎永遠不會過期。離了框架,我能夠活,我也會本身寫框架,我也在前端模塊化的路上本身摸索着,我也在前端如何更簡單,更快速開發的路上摸索着。難道有框架作了,我就坐吃山空等死嗎?html
前端太浮躁,我也無所謂成爲別人眼中的奇葩。我去作前端,我去作分離,我去寫後端,天天總會花一些時間在我喜歡的東西上。我知道我很傻逼,有的玩不玩,還去看代碼。那我沒辦法,我作奇葩很長時間了,由於我有本身的夢想,我有本身的追求。前端
請不要在我面前說,你這個東西人家都作了。作了怎麼了?人家作了,是你的嗎?人家作的時候前面不也有千千萬萬個死的淘汰的東西嗎?難道就由於人家作了我就不幹了?請不要目光短淺。鄙人也不隱藏我爲何作前端,如今列舉我作前端的理由,你和我同樣嗎?html5
以前發佈了ajax的通用解決方案,核心的ajax發佈請求,以及集成了輪詢。此次去外國網站逛逛,而後發現了ajax level2的上傳文件,因此就有了把ajax的上傳文件集成進去的想法,ajax方案的level2的改進就不介紹了,不清楚的可到前幾篇博客去看看。咱們直接切入主題。java
概念介紹:nginx
1. js的FormData:js中在新的版本中已經支持了FormData對象,能夠初始化一個空的form,或者初始化已經存在的form,瀏覽器測試代碼。git
2. 瀏覽器的支持:瀏覽器已支持input=file的時候查看文件,具體包括文件的大小(size)和類型(type),瀏覽器測試以下github
3. xmlhttprequest:支持發送(send方法)新的數據類型,包括DOMString
、Document
、FormData
、Blob
、File
、ArrayBuffer。具體參見ajax設計方案的規範
web
工具準備:ajax
1. 前端代碼
2. nginx服務器(分離)
3. IIS服務器(部署後臺)
4. 後臺代碼(webAPI)
什麼很少說,先貼代碼:
前端代碼:
/* * 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如下)
測試代碼以下:
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代碼以下:
<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上留言
這一次上傳版本,代碼作過變更,變更以下:
個人全棧書籤,此次更新整理了國內頂級互聯網和著名的一些互聯網公司的招聘網站,但願你們找到好工做,^_^