距离上一次博客大概好多好多时间了,感觉再不搞点东西出来,感觉就废了的感觉。这段时间回老家学习驾照,修养,然后7月底来上海求职(面了4家,拿了3家office),然后入职同程旅游,项目赶进度等等一系列的原因,导致没有太多时间去搞东西。感觉亏欠了好多,所以这次一次性补上。废话不多说了,我们直接进入主题。
介绍这次讲解的库的更新:
- ajax全局配置
- 请求参数的拓展(增加json)和重构优化
- 初始化参数类型检查
- 浏览器错误回收机制
- 增加ajax请求blob(二进制)类型
- 跨域问题的总结和支持
- npm打包发布
ajax全局配置
对于这个东西,相信大家都很有感触,在我们开发中的场景也很多,例如
- 接口名称前统一有"api/core"这个,但是在我们每次请求不想写这么多,就可以配置到baseURL中
- 请求接口后端定义一些公告参数,每次都要传输
- 为了一些业务,每次在http-header中设置 一些参数值
- 统一设置接口超时时间
- 统一错误、超时处理函数
- 发送请求前、获得请求参数后对参数处理
- ....
所以有了这个玩意,我只是定义一些常用的基础的,其他的大家可以根据自己业务需求进行拓展和改造,然后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上留言