当前位置: 首页 > Web前端 > HTML

我们公司是如何封装axios来处理百万流量中难得一见的问题的~

时间:2023-04-02 18:23:42 HTML

有梦想,有干货,微信搜索【大招走向世界】关注这位还在洗碗的洗碗智慧清晨的菜肴。本文已收录到GitHubhttps://github.com/qq449245884/xiaozhi,里面有完整的测试站点、资料和我的一线厂商访谈系列文章。本文是我们团队每周分享的内容,由导师整理分享。Eaxios是我们前端团队使用的库。是导师打包的。因为其他小伙伴也很好奇,所以只有这篇文章分享。正文开始~~EaxiosEaxios是一个基于axios封装的网络请求库。简化了服务端的响应内容和各种异常的处理,同时保持API与axios基本一致。开发背景如上图所示,是一个Ajax请求可能的输出结果。在前端,我们需要根据输出结果给用户不同的提示。请求取消:忽略网络异常:提示检查网络是否连通请求超时:提示网络慢,请切换到网络服务器异常:提示系统有问题是业务异常,并且前端需要根据错误码进行处理。最简单的就是一个消息提醒请求,请求成功:前端收到数据后更新界面。但是现有的Axios库并没有对异常结果进行很好的封装,AxiosPromisecatch中包含各种类型的错误,也没有提供错误码来识别请求失败的原因。而且很多服务端的接口都会返回自己的错误码,那么业务异常也需要在AxiosPromise中进行处理。此外,Axios本身有一些问题和限制,如下所述。如果设置axiosresponseType为json,则无法解析服务器返回的非JSON格式的响应内容,response.data为null。对于500等错误,响应内容会丢失,所以不要将responseType配置为json。对于用户来说很容易发现这个坑。ps:虽然axios官方文档说responseType是json,但实际上底层调用XMLHttpRequest的responseType是没有传值的,应该是为了避免这个问题。默认情况下,axios会调用默认的transformResponseps而不管HTTP响应状态和responseType:应该是为了避免前面的问题。JSON解析默认提供了响应处理函数,但这会影响性能(当响应内容值较多如500时,会导致页面卡顿)。transformResponse虽然可以对response进行转换,但是实际接收到的参数是response.data,所以无法判断具体情况来决定是否解析JSON。axiosthen和catch是根据validateStatus来判断的,用户处理起来比较麻烦。理想情况下,用户希望随后返回有效数据,并捕获返回各种错误情况:请求取消、网络异常、网络超时、服务器异常、服务器数据格式错误、业务异常。axios默认不处理content-type为application/x-www-form-urlencoded的requestbody,使用起来不方便。优化方案:如果将axiosresponseType设置为json,则不要将其传递给XMLHttpRequest,以免非JSON格式的响应内容丢失。axios根据响应头的content-type判断是否需要解析JSON,避免性能问题。通过请求拦截器,不将transformResponse配置传递给axios,将配置备份到其他字段,然后将响应对象存入响应拦截器。响应被传递给transformResponse进行处理。响应拦截器根据response提供的状态码、响应头和响应内容判断是否进行JSON转换。取消axiosvalidateStatus的配置选项。默认情况下,所有大于0的状态码都是正确的状态码,然后在axios拦截器中进行数据解析(非200也可能是json,所以200的json解析码要复用),并根据异常情况,抛出一个直观的错误对象。eaxios内置默认处理表单类型请求体使用说明,主要优化响应处理。除了以下部分,eaxios的api与axios是一致的:eaxios请求配置transformResponse传递参数,并且处理时机发生了变化。服务器响应内容后axios会调用transformResponse进行响应转换。eaxios响应后,会根据响应头和responseType自动解析JSON,然后将解析后的数据和response传递给transformResponse,transformResponse返回的数据最终会通过Promise解析给外部调用者。假设服务器返回的数据结构为{code:0,message:'success',data:{}},code为0表示响应正确,非0表示异常。接口请求的代码示例如下:consteaxios=require('eaxios');eaxios.defaults.transformResponse=[function(data,response){if(typeofdata==='object'){//If默认协议已成功解析JSON对象,则认为服务器响应成功。并且提供了错误代码if(data.code===0){returndata.data;}else{throweaxios.createError(data.message,data.code,response);}}else{//50x和其他服务异常Casethroweaxios.createError(data,response.config.responseError.SERVER_ERROR,response);}},];返回eaxios('https://run.mocky.io/v3/4f503449-0349-467e-a38a-c804956712b7').then((data)=>{console.log('success',data.id);}).catch((error)=>{console.log('failure',error.code);//UNKNOWN,REQUEST_OFFLINE,REQUEST_TIMEOUT,SERVER_ERROR,RESPONSE_INVALID和业务错误代码});ps:如果有服务单接口请求规范,可以使用eaxios.create创建适合不同接口规范的请求函数。eaxios的请求处理函数将只接收transformResponse转换后的数据。对于网络、超时、服务器端异常和业务异常,它会在catch中收到一个EaxiosError类型的错误对象。interfaceEaxiosErrorextendsError{配置:EaxiosRequestConfig;代码?:字符串;要求?:任何;响应?:EaxiosResponse;isAxiosError:布尔值;toJSON:()=>object;}错误处理函数可以根据错误码code来处理异常。code的可能值有UNKNOWN、REQUEST_OFFLINE、REQUEST_TIMEOUT、SERVER_ERROR、RESPONSE_INVALID等业务错误码。ps:如果想自定义错误码,可以在请求配置中添加配置项responseError。eaxios.defaults.responseError={REQUEST_OFFLINE:'1'REQUEST_OFFLINE};eaxios内部会自动序列化form类型的请求参数,所以将object传给data即可。代码示例下面以{code:0,message:'success',data:{}}等接口规范为例,演示如何使用eaxios。consteaxios=require('..');constrequest=eaxios.create({baseURL:'https://run.mocky.io/v3',timeout:30000,transformResponse:[function(data,response){如果(typeofdata==='object'){if(data.code===0){returndata.data;}else{throweaxios.createError(data.message,data.code,response);}}else{throweaxios.createError(data,response.config.responseError.SERVER_ERROR,response,);}},],});request.interceptors.response.use(function(response){返回响应;},function(error){if(error&&error.code){if(error.code==='UNKNOWN'){console.log('未知错误');}elseif(error.code==='REQUEST_OFFLINE'){console.log('网络未连接');}elseif(error.code==='REQUEST_TIMEOUT'){console.log('网络有点慢,请请求超时了');}elseif(error.code==='SERVER_ERROR'){控制台.log('系统有问题');}elseif(error.code==='RESPONSE_INVALID'){console.log('serverbug');}elseif(error.code==='10000'){//假设10000是登录会话过期console.log('Loginsessionexpired');}else{console.log('根据情况是要消息提示还是外部处理')}}throwerror;},);functionprintError(error){console.log(`code:${error.code},name:${error.name},message:${error.message},isAxiosError:${error.isAxiosError},stack:\n${error.stack}`,);}functionsuccess(){console.log('>>success');returnrequest('/4f503449-0349-467e-a38a-c804956712b7').then((data)=>{console.log('success',data);}).catch((error)=>{printError(error);});}functionfailure(){console.log('>>failure');返回请求('/42d7c21d-5ae6-4b52-9c2d-4c3dd221eba4').then((data)=>{console.log('success',data);}).catch((error)=>{printError(error);});}函数无效(){console.log('>>无效');返回请求('/1b23549f-c918-4362-9ac8-35bc275c09f0').then((data)=>{console.log('success',data);})。catch((error)=>{printError(error);});}functionserver_500(){console.log('>>server_500');返回请求('/2a9d8c00-9688-4d36-b2de-2dee5e81f5b3')。then((data)=>{console.log('success',data);}).catch((error)=>{printError(error);});}success().then(failure).then(invalid).then(server_500);/*log>>successsuccess{id:1}>>failureloginsessionfailurecode:10000,name:Error,message:error,isAxiosError:true,stack:...>>无效服务Sidebugcode:RESPONSE_INVALID,name:SyntaxError,message:UnexpectedtokenVinJSONatposition0,isAxiosError:true,stack:...>>server_500systemhasaproblemcode:SERVER_ERROR,name:Error,消息:...,stack:...*/compatibilityeaxios依赖URLSearchParams处理表单类型的请求参数,不支持的环境需要引入polyfillcore-jsrequire("core-js/modules/web.url-search-params.js")url-search-params-polyfill代码在部署后可能存在无法实时获知的BUG,为了解决这些BUG事后,花了很多时间关于日志调试,这里顺便推荐一个好用的BUG监控工具Fundebug,交流文章每周持续更新,微信搜索“大千世界”即可阅读即时更新(一两篇)早于博客),这篇文章在GitHub上https://github.com/qq449245884/xiaozhi已经收录,整理了我的很多文档,欢迎star和改进,可以参考考点另外,关注公众号,后台会回复福利,你可以看到福利,你懂的。