域名

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

时间:2010-12-5 17:23:32  作者:域名   来源:人工智能  查看:  评论:0
内容摘要:本文是我们团队每周分享的内容,该内容是由导师整理分享的。Eaxios 是我们前端团队自己在用的库,由导师封装的,因为其他小伙伴对它有所好奇,所以才有该篇的分享内容。正文开始~~EaxiosEaxios

本文是司封少我们团队每周分享的内容,该内容是处理由导师整理分享的。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 是没有传值的,应该是为了规避这个问题。云南idc服务商

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

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

Axios then 和 catch 是根据 validateStatus 决定的,使用者处理以来较为麻烦。

理想情况下,使用者希望 then 返回有效的数据,catch 返回各种错误情况:请求被取消、网络异常、网络超时、服务端异常、服务端数据格式错误、业务异常。

Axios 默认不处理 content-type 为 application/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: 1REQUEST_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 >> 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

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

【编辑推荐】

鸿蒙官方战略合作共建——HarmonyOS技术社区 云中的容器:你有哪些选择? 5G消息全力迈入发展期 什么是域名劫持?遇到域名劫持要怎么处理 自学编程,到底先选什么语言? 一文看完网络爬虫发展史
copyright © 2025 powered by 益强资讯全景  滇ICP备2023006006号-31sitemap