zoukankan      html  css  js  c++  java
  • 前端通信: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上留言

  • 相关阅读:
    ios端浏览器拍照上传到服务器,图片被旋转90度 php 解决方案
    wgs84 转百度经纬度坐标
    vue 编译大量空格警告问题总结 warning: Replace `↹↹` with `&#183;&#183;`
    微信sdk php签名方法整理
    Vue 使用百度地图组件
    php unicode转字符串
    第十篇、微信小程序-view组件
    第九篇、微信小程序-button组件
    第八篇、微信小程序-progress组件
    第七篇、微信小程序-video组件
  • 原文地址:https://www.cnblogs.com/GerryOfZhong/p/7575820.html
Copyright © 2011-2022 走看看