因为须要基于 axios 封装本人业务申请库,次要解决问题就是把通用操作封装,缩小反复操作,同样响应错误码进行集中管理,这样能够更加偏重在业务上的开发.
封装本人的业务插件,做到如下两点:
不减少用户应用老本(应用行为上同 axios 一样)可扩大保留原有行为假如插件的应用形式与 axios 齐全不一样,对于用户来说须要相熟老本,同样没方法做到平替(能够察看websocket-reconnect - npm第三方库,基于 websocket 进行封装,保留原生 websocket 相应的入参、事件。只是其根底上封装重连等性能)。
可扩大可扩大 毫无疑问也很重要:
能够提供默认值(缩小用户传参),容许内部去批改内部能够通过某种形式去干涉申请、响应(拦截器)接下来简略封装一下保留原有行为很好实现,咱们只须要把 axios 实例返回即可。
import axios, { AxiosRequestConfig } from 'axios';import { ResultCodeEnum, ErrorCodeMap } from './code';import { onRequestFulfilled, onRejected } from './requestInterceptor';import { onResponseFulfilled, onResponseRejected } from './responseInterceptor';// 默认参数const defaultOptions: AxiosRequestConfig = { baseURL: '', timeout: 15000,};// 扩大参数export interface Options extends AxiosRequestConfig { getToken?: () => string; loginOut?: () => void; notify: (msg: string) => void;}// 导出申请状态码export { ResultCodeEnum, ErrorCodeMap };// 导出申请办法export default function request(options?: Options) { // 合并选项 let optionsConfig: Options; if (options) { optionsConfig = { ...options, ...defaultOptions, notify: options?.notify && typeof options.notify === 'function' ? options.notify : (message) => { console.error(message); }, }; } else { optionsConfig = { ...defaultOptions, notify: (message) => { console.error(message); }, }; } // 创立实例 const instance = axios.create(optionsConfig); // 增加申请拦截器 instance.interceptors.request.use((config) => { return onRequestFulfilled(config, optionsConfig); }, onRejected); // 增加响应拦截器 instance.interceptors.response.use( (response) => { return onResponseFulfilled(response, optionsConfig); }, (error) => { return onResponseRejected(error, optionsConfig); } ); return instance;}// requestInterceptor.tsimport { AxiosError, AxiosRequestConfig } from 'axios';import { Options } from './request';export function onRequestFulfilled( config: AxiosRequestConfig, optionsConfig: Options) { if (config.headers) { if (optionsConfig && optionsConfig.getToken && optionsConfig.getToken()) { config.headers.Authorization = optionsConfig.getToken(); } } return config;}export function onRejected(error: AxiosError) { return Promise.reject(error);}// responseInterceptor.tsimport { AxiosError, AxiosResponse } from 'axios';import { ResultCodeEnum } from './code';import { Options } from './request';export function onResponseFulfilled( response: AxiosResponse, optionsConfig: Options) { const { data } = response; if (data.code !== ResultCodeEnum.SUCCESS) { optionsConfig.notify(data.message); if ( data.code === ResultCodeEnum.TOKEN_EXPIRE || data.code === ResultCodeEnum.TOKEN_FAIL ) { if (optionsConfig && optionsConfig.loginOut) { optionsConfig.loginOut(); } } return Promise.reject(new Error(data.message || 'Error')); } return data;}export function onResponseRejected(error: AxiosError, optionsConfig: Options) { // 解决 500 状态码 if (error.response) { const { status } = error.response; if (status === 500) { optionsConfig.notify('服务开小差了!!!'); } else if (status === 404) { optionsConfig.notify('资源找不到!!!'); } else if (status === 401) { optionsConfig.notify('无权限拜访!!!'); } else if (status === 403) { optionsConfig.notify('回绝拜访!!!'); } } else { // 申请超时 if (error.code === 'ECONNABORTED') { optionsConfig.notify('申请超时'); } } return Promise.reject(error);}// code.tsenum ResultCodeEnum { SUCCESS = 'SUCCESS', // 操作胜利 BIZ_ERROR = 'BIZ_ERROR', // 业务解决异样 INTERFACE_SYSTEM_ERROR = 'INTERFACE_SYSTEM_ERROR', // 内部接口调用异样 CONNECT_TIME_OUT = 'CONNECT_TIME_OUT', // 零碎超时 NULL_ARGUMENT = 'NULL_ARGUMENT', // 参数为空 ILLEGAL_ARGUMENT = 'ILLEGAL_ARGUMENT', // 参数不非法 ILLEGAL_REQUEST = 'ILLEGAL_REQUEST', // 非法申请 METHOD_NOT_ALLOWED = 'METHOD_NOT_ALLOWED', // 申请办法不容许 ILLEGAL_CONFIGURATION = 'ILLEGAL_CONFIGURATION', // 配置不非法 ILLEGAL_STATE = 'ILLEGAL_STATE', // 状态不非法 ENUM_CODE_ERROR = 'ENUM_CODE_ERROR', // 谬误的枚举编码 LOGIC_ERROR = 'LOGIC_ERROR', // 逻辑谬误 CONCURRENT_ERROR = 'CONCURRENT_ERROR', // 并发异样 ILLEGAL_OPERATION = 'ILLEGAL_OPERATION', // 非法操作 REPETITIVE_OPERATION = 'REPETITIVE_OPERATION', // 反复操作 NO_OPERATE_PERMISSION = 'NO_OPERATE_PERMISSION', // 无操作权限 RESOURCE_NOT_FOUND = 'RESOURCE_NOT_FOUND', // 资源不存在 RESOURCE_ALREADY_EXIST = 'RESOURCE_ALREADY_EXIST', // 资源已存在 TYPE_UN_MATCH = 'TYPE_UN_MATCH', // 类型不匹配 FILE_NOT_EXIST = 'FILE_NOT_EXIST', // 文件不存在 LIMIT_BLOCK = 'LIMIT_BLOCK', // 申请限流阻断 TOKEN_FAIL = 'TOKEN_FAIL', // token校验失败 TOKEN_EXPIRE = 'TOKEN_EXPIRE', // token过期 REQUEST_EXCEPTION = 'REQUEST_EXCEPTION', // 申请异样 BLOCK_EXCEPTION = 'BLOCK_EXCEPTION', // 接口限流降级 SYSTEM_ERROR = 'SYSTEM_ERROR', // ❌零碎异样}const ErrorCodeMap = { [ResultCodeEnum.SUCCESS]: '操作胜利', [ResultCodeEnum.BIZ_ERROR]: '业务解决异样', [ResultCodeEnum.INTERFACE_SYSTEM_ERROR]: '内部接口调用异样', [ResultCodeEnum.CONNECT_TIME_OUT]: '零碎超时', [ResultCodeEnum.NULL_ARGUMENT]: '参数为空', [ResultCodeEnum.ILLEGAL_ARGUMENT]: '参数不非法', [ResultCodeEnum.ILLEGAL_REQUEST]: '非法申请', [ResultCodeEnum.METHOD_NOT_ALLOWED]: '申请办法不容许', [ResultCodeEnum.ILLEGAL_CONFIGURATION]: '配置不非法', [ResultCodeEnum.ILLEGAL_STATE]: '状态不非法', [ResultCodeEnum.ENUM_CODE_ERROR]: '谬误的枚举编码', [ResultCodeEnum.LOGIC_ERROR]: '逻辑谬误', [ResultCodeEnum.CONCURRENT_ERROR]: '并发异样', [ResultCodeEnum.ILLEGAL_OPERATION]: '非法操作', [ResultCodeEnum.REPETITIVE_OPERATION]: '反复操作', [ResultCodeEnum.NO_OPERATE_PERMISSION]: '无操作权限', [ResultCodeEnum.RESOURCE_NOT_FOUND]: '资源不存在', [ResultCodeEnum.RESOURCE_ALREADY_EXIST]: '资源已存在', [ResultCodeEnum.TYPE_UN_MATCH]: '类型不匹配', [ResultCodeEnum.FILE_NOT_EXIST]: '文件不存在', [ResultCodeEnum.LIMIT_BLOCK]: '申请限流阻断', [ResultCodeEnum.TOKEN_FAIL]: 'token校验失败', [ResultCodeEnum.TOKEN_EXPIRE]: 'token过期', [ResultCodeEnum.REQUEST_EXCEPTION]: '申请异样', [ResultCodeEnum.BLOCK_EXCEPTION]: '接口限流降级', [ResultCodeEnum.SYSTEM_ERROR]: '❌零碎异样',};export { ResultCodeEnum, ErrorCodeMap };下面封装只做几件事:
...