有幻想,有干货,微信搜寻 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。

本文是咱们团队每周分享的内容,该内容是由导师整顿分享的。Eaxios 是咱们前端团队本人在用的库,由导师封装的,因为其余小伙伴对它有所好奇,所以才有该篇的分享内容。

注释开始~~

Eaxios

Eaxios 是基于 axios 封装的网络申请库,在放弃 API 与 axios 基本一致的状况下,简化服务端响应内容和各种异常情况的解决。

开发背景

如上图所示,是一次 Ajax 申请可能输入的后果,在前端咱们须要依据输入后果给用户不同的提醒。

  • 申请被勾销:疏忽
  • 网络异样:提醒查看是否连贯网络
  • 申请超时:提醒网络慢,请切换网络
  • 服务器异样:提醒零碎出问题了
  • 响应解析失败:同上,且能够进行谬误日志上报
  • 申请失败:这种状况通常是业务异样,前端须要依据错误码进行相应的解决,最简略的就是音讯揭示
  • 申请胜利:前端拿到数据后更新界面

然而,现有的 Axios 库对于异样后果没有提供较好的封装,Axios Promise catch 里蕴含各种类型的谬误,而且没有提供错误码来辨认申请失败的起因。而且很多服务端接口会返回本人的错误码,这样在 Axios Promise then 里也须要解决业务异样。

此外,Axios 自身如下所述的一些问题和局限性。

  • 如果设置 Axios responseType 为 json 时,服务端返回的非 JSON 格局的响应内容会因为无奈解析,response.data 为 null

    对于 500 等谬误,响应内容会失落,所以不要去配置 responseType 为 json,对于使用者来说容易采到这个坑。

    ps:尽管 Axios 官网文档申明 responseType 是 json,实际上底层调用 XMLHttpRequest 的 responseType 是没有传值的,应该是为了躲避这个问题。

  • Axios 默认不论 HTTP 响应状态和 responseType 是什么,都会调用默认的 transformResponse

    ps:应该是为了躲避上一个问题,默认提供了一个响应处理函数进行 JSON 解析,然而这会影响性能(500 等响应内容值较多时,会造成页面卡顿)。尽管 transformResponse 能够转换 response,理论接管到的参数是 response.data,所以无奈判断具体情况来决定是否进行解析 JSON。

  • Axios then 和 catch 是依据 validateStatus 决定的,使用者解决以来较为麻烦。

    现实状况下,使用者心愿 then 返回无效的数据,catch 返回各种谬误状况:申请被勾销、网络异样、网络超时、服务端异样、服务端数据格式谬误、业务异样。

  • Axios 默认不解决 content-typeapplication/x-www-form-urlencoded 类型的申请体,应用起来不够不便

优化计划:

  • 如果设置 Axios responseType 为 json 时,不要传给传 XMLHttpRequest,以防止非 JSON 格局的响应内容失落
  • Axios 依据响应头的 content-type 判断是否须要解析 JSON,以防止性能问题

    通过申请拦截器实现不给 Axios 传递 transformResponse 配置,且将配置备份到其余字段上,而后在响应拦截器中将响应对象 response 传递给 transformResponse 解决。响应拦截器依据 response 提供的状态码、响应头和响应内容判断是否要进行 JSON 转换。

  • 勾销 Axios validateStatus 的配置选项,默认所有大于 0 的状态码都是正确的状态码,而后在 Axios 拦截器 then 中进行数据解析(非 200 的可能也是 JSON,所以要复用 200 的 JSON 解析代码),并且依据异常情况抛出直观的谬误对象
  • 内置默认解决表单类型的申请体

用法说明

eaxios 次要对响应的解决做了一些优化,除了以下局部,eaxios 的 api 与 axios 保持一致:

  • eaxios 申请配置的 transformResponse 传参和解决机会产生了变动

    axios 在服务端响应内容后就会调用 transformResponse 进行响应转换,eaxios 响应后外部主动依据响应头和 responseType 进行 JSON 解析,而后将解析后的数据和 response 传给 transformResponse,transformResponse 返回的数据最终会被 Promise resovle 给内部调用者。

    假如服务端返回的数据结构为 { code: 0, message: 'success', data: {} },code 为 0 示意正确的响应,非 0 示意异样,接口申请的代码示例如下所示:

    const eaxios = require('eaxios');eaxios.defaults.transformResponse = [  function (data, response) {    if (typeof data === 'object') {      // 默认约定有胜利解析 JSON 对象,就认为服务端胜利响应,且有提供错误码      if (data.code === 0) {        return data.data;      } else {        throw eaxios.createError(data.message, data.code, response);      }    } else {      // 50x 等服务异常情况      throw eaxios.createError(        data,        response.config.responseError.SERVER_ERROR,        response      );    }  },];return 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 的申请处理函数 then 只会接管到 transformResponse 转换后的数据,对于网络、超时、服务端异样和业务异样等问题,会在 catch 接管一个 EaxiosError 类型的谬误对象。

    interface EaxiosError<T = any> extends Error {  config: EaxiosRequestConfig;  code?: string;  request?: any;  response?: EaxiosResponse<T>;  isAxiosError: boolean;  toJSON: () => object;}

    谬误处理函数能够依据错误码 code 来解决异样,code 可能的值为 UNKNOWN、REQUEST_OFFLINE、REQUEST_TIMEOUT、SERVER_ERROR、RESPONSE_INVALID 和其余业务错误码。

    ps:如果要定制错误码,能够在申请配置中增加配置项 responseError

    eaxios.defaults.responseError = {  REQUEST_OFFLINE: '1'REQUEST_OFFLINE};
  • eaxios 外部会主动序列化表单类型的申请参数,所以次要传对象给 data 就行了。

代码示例

上面以 { code: 0, message: 'success', data: { } } 这样的接口标准为例,演示如何应用 eaxios。

const eaxios = require('..');const request = eaxios.create({  baseURL: 'https://run.mocky.io/v3',  timeout: 30000,  transformResponse: [    function (data, response) {      if (typeof data === 'object') {        if (data.code === 0) {          return data.data;        } else {          throw eaxios.createError(data.message, data.code, response);        }      } else {        throw eaxios.createError(          data,          response.config.responseError.SERVER_ERROR,          response,        );      }    },  ],});request.interceptors.response.use(  function (response) {    return response;  },  function (error) {    if (error && error.code) {      if (error.code === 'UNKNOWN') {        console.log('未知谬误');      } else if (error.code === 'REQUEST_OFFLINE') {        console.log('网络未连贯');      } else if (error.code === 'REQUEST_TIMEOUT') {        console.log('网络有点慢,申请超时了');      } else if (error.code === 'SERVER_ERROR') {        console.log('零碎出问题了');      } else if (error.code === 'RESPONSE_INVALID') {        console.log('服务端 bug');      } else if (error.code === '10000') {        // 假如 10000 为登录会话过期        console.log('登录会话生效');      } else {        console.log('依据状况是否要音讯提醒,还是内部解决')      }    }    throw error;  },);function printError(error) {  console.log(    `code: ${error.code}, name: ${error.name}, message: ${error.message}, isAxiosError: ${error.isAxiosError}, stack:\n${error.stack}`,  );}function success() {  console.log('>> success');  return request('/4f503449-0349-467e-a38a-c804956712b7')    .then((data) => {      console.log('success', data);    })    .catch((error) => {      printError(error);    });}function failure() {  console.log('>> failure');  return request('/42d7c21d-5ae6-4b52-9c2d-4c3dd221eba4')    .then((data) => {      console.log('success', data);    })    .catch((error) => {      printError(error);    });}function invalid() {  console.log('>> invalid');  return request('/1b23549f-c918-4362-9ac8-35bc275c09f0')    .then((data) => {      console.log('success', data);    })    .catch((error) => {      printError(error);    });}function server_500() {  console.log('>> server_500');  return request('/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 }>> failure登录会话生效code: 10000, name: Error, message: error, isAxiosError: true, stack: ...>> invalid服务端 bugcode: RESPONSE_INVALID, name: SyntaxError, message: Unexpected token V in JSON at position 0, isAxiosError: true, stack: ...>> server_500零碎出问题了code: SERVER_ERROR, name: Error, message: ...,  stack: ...*/

兼容性

eaxios 依赖 URLSearchParams 解决表单类型的申请参数,不反对的环境须要引入响应的 polyfill

  • core-js

    require("core-js/modules/web.url-search-params.js")
  • url-search-params-polyfill

代码部署后可能存在的BUG没法实时晓得,预先为了解决这些BUG,花了大量的工夫进行log 调试,这边顺便给大家举荐一个好用的BUG监控工具 Fundebug。

交换

文章每周继续更新,能够微信搜寻「 大迁世界 」第一工夫浏览和催更(比博客早一到两篇哟),本文 GitHub https://github.com/qq449245884/xiaozhi 曾经收录,整顿了很多我的文档,欢送Star和欠缺,大家面试能够参照考点温习,另外关注公众号,后盾回复福利,即可看到福利,你懂的。