前端通信:ajax设计方案(六)--- 全局配置、请求格式拓展和优化、请求二进制类型、浏览器错误搜集以及npm打包发布

距离上一次博客大概好多好多时间了,感觉再不搞点东西出来,感觉就废了的感觉。这段时间回老家学习驾照,修养,然后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上留言

 

posted on 2017-09-25 10:05  仲强  阅读(770)  评论(2编辑  收藏

导航

统计