前端通訊:ajax設計方案(三)--- 集成ajax上傳技術

在此以前讓我感慨一下如今的前端開發的氛圍。我遇到好多人,給個人觀念都是,這個東西這個框架有了,那個東西那個框架作了,前端嘛,學幾個框架,這個拼湊一下那個拼湊一下就行了。其實我想問,東西都框架作了,那你會什麼?會吹牛逼?會撕逼?javascript

我在簡歷上寫專一原聲js,曾經被幾我的笑過。我一直搞不懂,框架會過期,基礎永遠不會過期。離了框架,我能夠活,我也會本身寫框架,我也在前端模塊化的路上本身摸索着,我也在前端如何更簡單,更快速開發的路上摸索着。難道有框架作了,我就坐吃山空等死嗎?html

前端太浮躁,我也無所謂成爲別人眼中的奇葩。我去作前端,我去作分離,我去寫後端,天天總會花一些時間在我喜歡的東西上。我知道我很傻逼,有的玩不玩,還去看代碼。那我沒辦法,我作奇葩很長時間了,由於我有本身的夢想,我有本身的追求。前端

請不要在我面前說,你這個東西人家都作了。作了怎麼了?人家作了,是你的嗎?人家作的時候前面不也有千千萬萬個死的淘汰的東西嗎?難道就由於人家作了我就不幹了?請不要目光短淺。鄙人也不隱藏我爲何作前端,如今列舉我作前端的理由,你和我同樣嗎?html5

    1. 對接UI,須要涉獵頁面設計,佈局和美化。學會去審美,學會站在用戶角度去看本身的東西。固然我不否定,UI妹子也多
    2. 對接js,對前端核心技術的考驗。對於頁面功能實現、新舊技術兼容和捨棄、如何寫出高效可維護代碼的思考
    3. 對接架構,前端性能優化,程序健壯性和容錯性,各類框架資源整合使用,從DNS解析到頁面渲染到你眼前的各類過程的跨域學習
    4. 對接後端,新老技術的變化,永遠不是前端,後端同樣須要去配合着去改變。因此懂後端,設計後端,寫後端,永遠都須要你去懂得
    5. 對接服務器,反向代理,負載均衡,請求分發容錯整合等等難道不須要懂嗎?難道只敲個js就夠了?
    6. 前端的將來,任何項目的使用和展現,都離不開前端。由於前端第一接觸是用戶,是發展的最核心的資源。前端是站在整個戰線第一線的。
    7. 最重要的。前端剛起步,不是很成熟,能夠接觸全部的原聲和底層,優化,開發,調試,甚至改變世界,都是有可能的。後端太成熟,接觸太多都是框架,突出重圍,須要更深的積累和叛逆。
    8. 最重要的,前端相對來講,薪水前期仍是很好的。畢竟還要生活,詩和遠方都不及麪包重要,活着,一切纔有可能。

 

  以前發佈了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方法)新的數據類型,包括DOMStringDocumentFormDataBlobFileArrayBuffer。具體參見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上留言

 

這一次上傳版本,代碼作過變更,變更以下:

  1. 增長FormData數據傳輸方法(postFormData),若是判斷到瀏覽器不支持FormData,則自動使用默認原始的數據傳輸
  2. 新增各類類型判斷方法,判斷類型
  3. 更新each方法,判斷若是傳入參數obj爲數組並且瀏覽器支持h5的新特性直接用數組的forEach方法

 

個人全棧書籤,此次更新整理了國內頂級互聯網和著名的一些互聯網公司的招聘網站,但願你們找到好工做,^_^

github地址:https://github.com/GerryIsWarrior/MyBookmarks

相關文章
相關標籤/搜索