1. 程式人生 > >框架基礎:ajax設計方案(六)--- 全局配置、請求格式拓展和優化、請求二進制類型、瀏覽器錯誤搜集以及npm打包發布

框架基礎:ajax設計方案(六)--- 全局配置、請求格式拓展和優化、請求二進制類型、瀏覽器錯誤搜集以及npm打包發布

rri seve win 最大 regexp isempty lee 出現問題 hub

距離上一次博客大概好多好多時間了,感覺再不搞點東西出來,感覺就廢了的感覺。這段時間回老家學習駕照,修養,然後7月底來上海求職(面了4家,拿了3家office),然後入職同程旅遊,項目趕進度等等一系列的原因,導致沒有太多時間去搞東西。感覺虧欠了好多,所以這次一次性補上。廢話不多說了,我們直接進入主題。

介紹這次講解的庫的更新

  •   ajax全局配置
  •   請求參數的拓展(增加json)和重構優化
  •   初始化參數類型檢查
  •   瀏覽器錯誤回收機制
  •   增加ajax請求blob(二進制)類型
  •   跨域問題的總結和支持
  •   npm打包發布

ajax全局配置

  對於這個東西,相信大家都很有感觸,在我們開發中的場景也很多,例如

  1. 接口名稱前統一有"api/core"這個,但是在我們每次請求不想寫這麽多,就可以配置到baseURL中
  2. 請求接口後端定義一些公告參數,每次都要傳輸
  3. 為了一些業務,每次在http-header中設置 一些參數值
  4. 統一設置接口超時時間
  5. 統一錯誤、超時處理函數
  6. 發送請求前、獲得請求參數後對參數處理
  7. ....

  所以有了這個玩意,我只是定義一些常用的基礎的,其他的大家可以根據自己業務需求進行拓展和改造,然後push一個分支,我會討論協商之後采納的。代碼如下:

  PS:這公共參數玩意我忘了去限制了,如果傳輸和其他初始化參數一樣的會覆蓋的,下個版本進行改進,見諒。

        //通過拋出的config方法設置全局參數
        ajax.config({
            baseURL: ‘‘,                //通用url前綴
            requestHeader: {},          //公共頭部
            publicData: {},             //公共參數
            timeout: 5000,              //超時時間
            responseType: ‘json‘,       //response參數類型,默認‘json‘
contentType: ‘‘, //請求參數類型(‘‘、‘json‘、‘form‘) withCredentials: true, //是否啟用跨域憑證傳輸 isOpenErr: true, //是否開啟瀏覽器錯誤回收 errURL: ‘‘, //瀏覽器錯誤回收地址 //請求發送前對數據進行處理 transformRequest: function (data) { return data; }, //得到正確請求後做的處理 transformResponse: function (data) { return data; }, //請求錯誤處理 errorEvent: function (x, xx, xxx) { }, //請求超時處理 timeoutEvent: function (code, e) { } })

請求參數的拓展(增加json)和重構優化

  在之前寫的庫中,只針對請求做了通用的請求和form請求,但是針對常用的請求類型json格式沒有支持,所以這次將這個參數進行支持(主要我們項目中用到了,但是我寫的庫沒有,所以支持)

  其次所謂的重構優化,只是感覺之前的代碼太TM挫了。不利於拓展和維護,所以這次將它進行優化。

            //參數處理
            if (ajaxSetting.data) {     //有數據做參數處理
                switch (ajaxSetting.contentType) {
                    case ‘‘:    //通用請求
                        tool.each(tool.MergeObject(ajaxSetting.data, ajaxSetting.publicData), function (item, index) {
                            sendData += (index + "=" + item + "&")
                        });
                        sendData = sendData.slice(0, -1);
                        ajaxSetting.requestHeader[‘Content-Type‘] = ‘application/x-www-form-urlencoded‘
                        break
                    case ‘json‘:    //json請求
                        sendData = JSON.stringify(tool.MergeObject(ajaxSetting.data, ajaxSetting.publicData))
                        ajaxSetting.requestHeader[‘Content-Type‘] = ‘application/json‘
                        break
                    case ‘form‘:    //form請求
                        if (!tool.isEmptyObject(ajaxSetting.publicData)) {
                            tool.each(ajaxSetting.publicData, function (item, index) {
                                ajaxSetting.data.append(index, item)
                            })
                        }
                        sendData = ajaxSetting.data
                        break
                }
                //請求前處理參數
                sendData = ajaxSetting.transformRequest(sendData)

                //判斷請求類型
                if (ajaxSetting.type === ‘get‘) {
                    xhr.open(ajaxSetting.type, tool.checkRealUrl(ajaxSetting) + ‘?‘ + sendData, ajaxSetting.async)
                } else {
                    xhr.open(ajaxSetting.type, tool.checkRealUrl(ajaxSetting), ajaxSetting.async)
                }
            } else {
                xhr.open(ajaxSetting.type, ajaxSetting.baseURL + ajaxSetting.url, ajaxSetting.async)
            }

  

初始化參數類型檢查

  初始化參數檢查這個功能主要在每個請求中,可能不是定義的參數都想傳輸的,比如我做瀏覽器錯誤回收的時候,我只想將這個錯誤的信息發送到錯誤回收地址,我不需要做任何處理,只需要發出去,不管成不成功。所以我只有post2個參數,地址和錯誤信息。如果不做參數檢查,合並參數的時候,會把undefind合並到初始化參數中,導致程序宕機,容錯性、健壯性特別差,這樣的程序當雖然是我們都不想看到和去寫的,所以做了這塊。代碼如下:

  類型檢查代碼:

        //類型判斷
        is: (function checkType() {
            var is = {
                types: ["Array", "Boolean", "Date", "Number", "Object", "RegExp", "String", "Window", "HTMLDocument", "function", "FormData"]
            };
            for (var i = 0, c; c = is.types[i++];) {
                is[c] = (function (type) {
                    return function (obj) {
                        var temp;
                        if (type === "function") {
                            temp = typeof obj == type
                        } else {
                            temp = Object.prototype.toString.call(obj) == "[object " + type + "]";
                        }
                        return temp;
                    }
                })(c);
            }
            ;
            return is;
        })(),

  批量處理代碼:

        //批量檢查數據類型
        checkDataTypeBatch: function (obj, objType) {
            var temp = true;
            tool.each(obj, function (value, key) {
                var typeName = objType[key], tempOutput;
                if (tool.is.Array(typeName)) {
                    tool.each(typeName, function (item) {
                        tempOutput = tempOutput || tool.is[item](value);
                    })
                } else {
                    tempOutput = tool.is[typeName](value)
                }
                //如果格式不對,將錯誤數據恢復到初始化數據
                if (!tempOutput) {
                    obj[key] = initParam[key]
                }
            })
            return temp;
        },

  初始化數據和初始化數據類型

    //默認參數
    var initParam = {
        url: "",
        type: "",
        baseURL: ‘‘,
        data: {},
        async: true,
        requestHeader: {},
        publicData: {},
        timeout: 5000,
        responseType: ‘json‘,
        contentType: ‘‘,
        withCredentials: false,
        isOpenErr: false,
        errURL: ‘‘,
        transformRequest: function (data) {
            return data;
        },
        transformResponse: function (data) {
            return data;
        },
        successEvent: function (data) {
        },
        errorEvent: function (x, xx, xxx) {
        },
        timeoutEvent: function (code, e) {
        }
    };
    //初始化參數固定類型檢查
    var initParamType = {
        url: "String",
        type: "String",
        baseURL: ‘String‘,
        data: [‘Object‘, ‘FormData‘],
        async: ‘Boolean‘,
        requestHeader: ‘Object‘,
        publicData: ‘Object‘,
        timeout: ‘Number‘,
        responseType: ‘String‘,
        contentType: ‘String‘,
        withCredentials: ‘Boolean‘,
        isOpenErr: ‘Boolean‘,
        errURL: ‘String‘,
        transformRequest: ‘function‘,
        transformResponse: ‘function‘,
        successEvent: ‘function‘,
        errorEvent: ‘function‘,
        timeoutEvent: ‘function‘
    };

  PS:可能不會將所有的所有的都考慮進去,但是這些已經能完成我暫時的需求了,如果想對這個方法做補充的,可以直接郵件或者github提交分支,然後驗證討論完善會合並到master上的

瀏覽器錯誤回收機制

  瀏覽器錯誤回收這個概念,一般的公司是不會做的,只有那種針對廣泛用戶,廣泛瀏覽器兼容性的產品才會做。因為可能在主流瀏覽器上會出現問題,畢竟將市面上所有瀏覽器都做測試,對於公司的測試人員來說都是一個極大的工作量,所以相對來說肯定有很多忽略的,但是對於公司來說,每個客戶都是一種珍貴的資源,在不破壞主流的基礎上還是需要兼容的。所以回收這些錯誤,才顯得重要。

  其次,還有更重要的一點,對於線上的bug和隱形的bug,永遠是重大的生產問題,在大公司會被問責的。所以瀏覽器錯誤搜集才顯得更加重要,在沒有被擴大之前能及時回收到才是最重要的。因為我曾在極客頭條這個網站遇到過,他們更新版本後登錄接口請求參數變化了,但是對於前端來說並沒有響應處理,導致登錄不上。這樣的問題,如果發生在淘寶上的話,一個部門會直接被問責的。

  so,有這個想法就做了,而且我這主要寫了前端通信,所以順便加進去了。(PS:現在只做了瀏覽器的錯誤搜集處理,對於ajax的錯誤處理沒有監控,下個版本補上。畢竟接口的404等錯誤,瀏覽器onerror是不會觸發的)

        //監控瀏覽器的錯誤日誌
        setOnerror: function () {
            window.onerror = function (errInfo, errUrl, errLine) {
                tempObj.post(initParam.errURL, {
                    errInfo: errInfo,               //錯誤信息
                    errUrl: errUrl,                 //錯誤地址
                    errLine: errLine,               //錯誤行號
                    Browser: navigator.userAgent    //瀏覽器版本
                })
            }
        },

  so,看完了是不是很簡單,其實就是這麽簡單,ajax接口錯誤監控暫時沒有最好的方案,因為在ajax考慮到瀏覽器的兼容性錯誤地方不同,而且要將錯誤回收地址的錯誤忽略掉,而且要考慮什麽時候切入監控這個點最好等等,而且要配置進主流程能動態配置,哎不說了,下期吧。順便下期將前端接口容錯機制加上去,比如監控到404、503、403等錯誤信息,前端接口自動將請求地址切換到備用地址,保證程序的健壯性。

增加ajax請求blob(二進制)類型

  這個功能是之前想做的,不知道有沒有真實場景進行使用的。我做的測試只是針對一個圖片做的測試,請求一個二進制圖片,然後反顯。但是後期的場景可能比較重要,瀏覽器通過ajax流式下載文件等等,這個功能待定吧。

        //獲取blob數據集代碼
        obtainBlob: function (type, url, data, successEvent, errorEvent, timeoutEvent) {
            var ajaxParam = {
                type: type,
                url: url,
                data: data,
                responseType: ‘blob‘,
                successEvent: successEvent,
                errorEvent: errorEvent,
                timeoutEvent: timeoutEvent
            };
            ajax.common(ajaxParam);
        },

        //test ObtainBlob(確保地址正確)測試代碼
        ajax.obtainBlob("get","http://10.73.1.198:9999/Scripts/lei.jpg", ‘‘, function (getData) {
            var reader = new FileReader();
            reader.readAsDataURL(getData)
            reader.onload = function (e) {
                document.querySelector("#imgICO").setAttribute(‘src‘,e.target.result)
            }
            console.log(typeof getData);
        });

關於跨域的問題支持

  跨域隔離:瀏覽器的core中,針對跨域為了安全做了限制,在跨域的時候將不會把cookie等憑證的數據進行服務器和客戶端之間回傳。所以,為了更快的請求靜態資源,可以將本項目中的靜態資源放到不同的域中,這樣進行跨域了,所以傳輸的請求比較小,速度也更快

  但是,在多項目中,肯定會和其他項目組合作,so,有時候會需要這些憑證做一些自動登錄、身份驗證等功能。所以會需要進行憑證傳輸。

  在XMLHttprequest中有個屬性withCredentials,這個屬性控制前端是否傳輸憑證信息(全局配置中已加),當然服務器也需要設置跨域請求的頭部:"Access-Control-Allow-Credentials: true"。這樣就可以愉快的玩耍啦

npm打包發布

  這是最後一個了,也是完成一個關註的人的建議。在之前的博客中,有個朋友進行建議的,所以我進行了搜索、改造、發布、測試。所以時間周期有點長了。

  npm:ajax-js

  安裝:npm i ajax-js / yarn add ajax-js

  使用:在頁面中引入,然後使用

<template>
  <div id="app">
    select file:<input type="file" id="file1" accept="*"/><br/>
    <input type="button" id="upload" value="upload"/>
    <input type="button" id="uploadBig" value="uploadBig"/>
    <img id="imgICO"/>
  </div>
</template>

<script>
  import _ajax from ‘ajax-js‘
  export default {
    name: ‘app‘,
    created(){
      _ajax.get(‘http://10.73.1.198:9999/api/cores/getAjax/‘,{name:‘get請求成功‘,age:11},function (res) {
        console.log(res.name)
      })
      //test post
      _ajax.post("http://10.73.1.198:9999/api/cores/postAjax/",{name:‘post請求測試成功‘,age:1},function(getData){
        console.log(getData.name);
      });
//
      var formData = new FormData();
      formData.append("name", "post Form請求測試成功");
      formData.append("age", 11);
      _ajax.postFormData("http://10.73.1.198:9999/api/cores/postForm/",formData,function (res) {
        console.log(res.name)
      })
//
      //test post
//      _ajax.postJSON("http://10.73.1.198:9999/api/cores/postAjax/",{name:‘postJSON請求測試成功‘,age:1},function(getData){
//        console.log(getData.name);
//      });

      //test ObtainBlob(確保地址正確)
//      ajax.obtainBlob("get","http://10.73.1.198:9999/Scripts/lei.jpg", ‘‘, function (getData) {
//        var reader = new FileReader();
//        reader.readAsDataURL(getData)
//        reader.onload = function (e) {
//          document.querySelector("#imgICO").setAttribute(‘src‘,e.target.result)
//        }
//        console.log(typeof getData);
//      });

      //promise一般測試
      _ajax.promiseAjax(‘http://10.73.1.198:9999/api/cores/postReqSleep/‘,{name:‘promise高延遲接口測試1‘,age:123})
        .then(function (res) {
          console.log(res.name)
          return _ajax.promiseAjax(‘http://10.73.1.198:9999/api/cores/postAjax/‘,{name:‘promise一般接口測試2‘,age:456})
        }).then(function (res) {
        console.log(res.name)
      })
//
      //並發promise測試
      _ajax.promiseAjax(‘http://10.73.1.198:9999/api/cores/postAjax/‘,{name:‘promise並發接口測試3‘,age:123456})
        .then(function (res) {
          console.log(res.name)
          return _ajax.promiseAjax(‘http://10.73.1.198:9999/api/cores/postReqSleep/‘,{name:‘promise並發高延遲接口測試4‘,age:456789})
        }).then(function (res) {
        console.log(res.name)
      })
//
      var longTemp = 0;
      _ajax.longPolling(‘post‘,‘http://10.73.1.198:9999/api/cores/postAjax/‘,{name:‘輪詢測試‘,age:123456},function (res,that) {
        console.log(res.name+longTemp)
        longTemp+=1;
        if (longTemp === 10){
          that.stop = true;
        }
      },1000)
//




    },
    mounted(){
      //test post
      _ajax.postJSON("api/postAjax",{name:‘postJSON請求測試成功‘,age:1},function(getData){
        console.log(getData.name);
      });

      //test uploadFile
      document.querySelector("#upload").onclick = function () {
        var temp = _ajax.upload("http://10.73.1.198:9999/api/cores/upload/","#file1",1024*1024,[‘image/png‘],function(x){ })
        console.log(temp);
      };
//
//      //test uploadFile
      document.querySelector("#uploadBig").onclick = function () {
        JSON.parse(‘‘)
//            var temp = ajax.upload_big("api/cores/uploadBig/","#file1",1024*1024,"*",function(x){},function(count,all){console.log("當前傳輸進度:"+count+"/"+all);})
        var temp = _ajax.upload_big("http://10.73.1.198:9999/api/cores/uploadBig/","#file1",1024*1024,"*",function(x){},function(count,all){console.log("當前傳輸進度:"+count+"/"+all);})
        console.log(temp);
      };

    }
  }
</script>

<style>
  #app {
    font-family: ‘Avenir‘, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    color: #2c3e50;
    margin-top: 60px;
  }
</style>

  PS:這個是在vue中的進行測試的。測試結果如下。

技術分享

以下為不用npm安裝的測試,測試頁面在github上,後端接口用的.net,也在上面,看圖:

技術分享

  

看一般頁面的測試結果

  技術分享

錯誤搜集接口查看

技術分享

好啦,這個版本已經發布好了,有新的需求就籌劃下個版本的東西啦。最近在研究SSE,也就是前端的服務器推送玩意,準備這段時間總結出一套東西,順便針對這個技術本身的一些技術局限設計解決一些方案,比如SSE只能默認推送所有人,可以設計針對單個人去推送等等

代碼已集成github和npm打包:https://github.com/GerryIsWarrior/ajax / npm i ajax-js 點顆星星是我最大的鼓勵,有什麽問題可以博客、郵箱、github上留言

框架基礎:ajax設計方案(六)--- 全局配置、請求格式拓展和優化、請求二進制類型、瀏覽器錯誤搜集以及npm打包發布