我司是怎么封装 axios 来处理百万级流量中平时少见过的问题

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

正文开始~~

Eaxios

Eaxios 是基于 axios 封装的网络请求库,在保持 API 与 axios 基本一致的情况下,简化服务端响应内容和各种异常情况的处理。

开发背景

我司是怎么封装 axios 来处理百万级流量中平时少见过的问题

如上图所示,是一次 Ajax 请求可能输出的结果,在前端我们需要根据输出结果给用户不同的提示。

但是,现有的 Axios 库对于异常结果没有提供较好的封装,Axios Promise catch 里包含各种类型的错误,而且没有提供错误码来识别请求失败的原因。而且很多服务端接口会返回自己的错误码,这样在 Axios Promise then 里也需要处理业务异常。

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

优化方案:

用法说明

eaxios 主要对响应的处理做了一些优化,除了以下部分,eaxios 的 api 与 axios 保持一致:

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 创建适用于不同接口规范的请求函数。
interface EaxiosError extends Error {
  config: EaxiosRequestConfig;
  code?: string;
  request?: any;
  response?: EaxiosResponse;
  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
};

代码示例

下面以 { 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:
${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
>> success
success { id: 1 }
>> failure
登录会话失效
code: 10000, name: Error, message: error, isAxiosError: true, stack: ...
>> invalid
服务端 bug
code: 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

require("core-js/modules/web.url-search-params.js")
展开阅读全文

页面更新:2024-03-28

标签:表单   服务端   函数   流量   平时   接口   异常   对象   状态   错误   提示   类型   情况   业务   内容   数据   科技   网络

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top