Axios的封装

最近,参考了下以前的项目,每个项目的axios都有自己独立的主见,导致该起来,简直看看当时的逻辑,在看下传参,否责真的不方便改,废话不说了,解释下我是怎么封装的吧:

Step1:

        axios的引入: npm i axios ;这个就不废话了,大家都懂

        之后构建axios的基础模块: 

"use strict";
import axios from "axios";

const env = import.meta.env.MODE

let config = {
  baseURL: env === 'production' ? '' : '/development',
  timeout: 60 * 1000,
};

const _axios = axios.create(config);

_axios.interceptors.request.use(
  function (requestConfig) {
    return requestConfig;
  },
  function (error) {
    return Promise.reject(error);
  }
);

_axios.interceptors.response.use(
  function (response) {
    return response.data;
  },
  function (error) {
    return Promise.reject(error);
  }
);
export default _axios

 这个其实也是常规的内容,网络上随便找一下很多相同的内容,到了这里一般的准备工作也就over了。

Step 2 :自以为我对其进行了一下封装:

其实仔细考虑下,我们常规对axios的使用,无外乎集中情况,GET用来获取数据,POST用来创建数据,PUT用来更新数据,DELETE用来删除数据等等。。。

但是仔细考虑下,每次传递的参数结构其实都是在围绕axios的本身参数结构进行传递,如果不封装一下,代码简直乱的一团糟,看着也影响心情(本人有点代码洁癖,当然烦躁的时候,洁癖就不存在了)。

之后想着,把重复的代码部分进行重构整合一下,内容就这样:

import http from './axios';
import { codeObject } from './errorCode'

/**
 * 这里假设接口的返回格式为: { code : number , data : any , msg : string }
 */

/**
 * 接口调用后逻辑判断
 * @param res 接口返回的固定结构
 */
const finishedInterface = (res: any , streamType: string|undefined = "" ,resolve:any , reject : any ): void => {
  if ( streamType !== undefined ) {
    resolve( streamType === "BLOB" ? URL.createObjectURL(res) : res )
  } else {
    if( res.code === 200 ) {
      resolve( res.data )
    } else {
      const alertMessage:string = res.msg || codeObject[res.code] 
      // message.alert(alertMessage)
      reject(alertMessage)
    }
  }
}

/**
 * 获取请求令牌 token
 * @returns 
 */
export const getToken = (): string | null => {
  return localStorage.getItem('Bearer') ? localStorage.getItem('Bearer') : ''
}

/**
 * 接口的烤用核心逻辑
 * @param methods 调用的方法:["GET","PUT","POST","DELETE"]
 * @param url 接口路径
 * @param params 调用接口的关联参数
 * @param props axios其余配置
 * @param resultType 针对文件下载,可以确定文件状体啊喂BLOB还是原始的流
 * @returns 返回一个Promise Object ,可以通过Promise.then() 和Promise.catch()使用回调函数
 */
const httpRequest = (methods: string = "GET", url: string = "", params: Object = {}, props: any = {}, resultType: string | undefined = undefined): Promise<unknown> => {
  return new Promise((resolve: any, reject: any) => {
    http({
      method: "GET",
      headers: {
        "Authorization": `${getToken()}`,
        "TENANT-ID": localStorage.getItem('TENANT-ID'),
        ...(props.header ? props.header : {})
      },
      url: url || '/',
      [methods == 'GET' ? 'params' : 'data']: params,
      setTimeout: 1000 * 60, //超时时间
      ...props
    }).then((res: any) => {
      finishedInterface(res,resultType,resolve,reject)
    }).catch(err => {
      reject(err)
    })
  })
}
/**
 * GET ,获取接口
 * @param url 接口路径
 * @param params 接口参数
 * @param props axios其余配置
 * @returns 返回一个Promise Object ,可以通过Promise.then() 和Promise.catch()使用回调函数
 */
export const httpRequestGET = (url: string = "", params: Object = {}, props: any = {}): Promise<unknown> => {
  return httpRequest('GET', url, params, props);
}

/**
 * PUT , 数据推送接口
 * @param url 接口路径
 * @param params 接口参数
 * @param props axios其余配置
 * @returns 返回一个Promise Object ,可以通过Promise.then() 和Promise.catch()使用回调函数
 */
export const httpRequestPUT = (url: string = "", params: Object = {}, props: any = {}): Promise<unknown> => {
  return httpRequest('PUT', url, params, props);
}

/**
 * POST , 数据创建接口
 * @param url 接口路径
 * @param params 接口参数
 * @param props axios其余配置
 * @returns 返回一个Promise Object ,可以通过Promise.then() 和Promise.catch()使用回调函数
 */
export const httpRequestPOST = (url: string = "", params: Object = {}, props: any = {}): Promise<unknown> => {
  return httpRequest('POST', url, params, props);
}

/**
 * DELETE , 数据删除接口
 * @param url 接口路径
 * @param params 接口参数
 * @param props axios其余配置
 * @returns 返回一个Promise Object ,可以通过Promise.then() 和Promise.catch()使用回调函数
 */
export const httpRequestDELETE = (url: string = "", params: Object = {}, props: any = {}): Promise<unknown> => {
  return httpRequest('DELETE', url, params, props);
}

/**
 * 文件下载接口,封装方法
 * @param url 接口路径
 * @param params 接口参数
 * @param props axios其余配置
 * @param resultType 返回内容的类型 : BLOB格式 | 二进制流格式
 * @returns 返回一个Promise Object ,可以通过Promise.then() 和Promise.catch()使用回调函数
 */
export const httpRequestDOWNLOAD = (url: string = "", params: any = {}, props: any = {}, resultType: string = "BLOB"): Promise<unknown> => {
  return httpRequest('POST', url, params, { ...props, responseType: 'blob' }, resultType);
}

/**
 * 文件上传接口,封装方法
 * @param url 接口路径
 * @param files 上传的文件,需要进行确定,上传格式为File Array ,this is very important
 * @param params 接口参数
 * @param props axios其余配置
 * @returns 返回一个Promise Object ,可以通过Promise.then() 和Promise.catch()使用回调函数
 */
export const httpRequestUPLOAD = (url: string = "", files: Array<File> = [], params: any = {}, props: any = {}): Promise<unknown> => {
  const formData = new FormData();
  if (files.length > 0) {
    files.forEach((item: File, index: number) => {
      formData.append('files', item, index.toString())
    })
  }
  for (let key in params) {
    formData.append(key, params[key])
  }
  return httpRequest('POST', url, formData, props);
}

/**
 * 接口对象内容,其中包括了所有封装好的接口调用模式和逻辑
 */
export const httpRequestObject = {
  GET: httpRequestGET(),
  PUT: httpRequestPUT(),
  POST: httpRequestPOST(),
  DELETE: httpRequestDELETE(),
  DOWNLOAD: httpRequestDOWNLOAD(),
  UPLOAD: httpRequestUPLOAD(),
}

这里其实很多同行就很容易理解了,如果有更好的方式,各位也可以私信,互相提升一下。

Step 3 数据处理

每次接口调用完成,其实主要麻烦的事情就是对接口数据的整合、处理,尤其是针对错误的情况的提示和日志记录,这里我参考了下httpcode的返回值进行了简单的修改,这里是一个很灵活的地方,可以根据公司或者项目的规则进行自定义,当然很多开发过程中,返回的内容存在很多的不一致和特殊情况,如果这样的话,我一般会进行街区接口名字,之后通过Array.includes(interfaceName)进行判断黑名单的操作跳过错误认证。大家可以参考下,下面是一个ts文件来返回一个json对象:

interface CodeObject{
	[propName:string]:string
}

export const codeObject:CodeObject = {
	"ECONNABORTED": "连接超时",
	"ERR_BAD_RESPONSE": "服务端错误",
	"100": "继续",
	"101": "切换协议",
	"200": "请求成功",
	"201": "已创建",
	"202": "已接受",
	"203": "非授权信息",
	"204": "无内容",
	"205": "重置内容",
	"206": "部分内容",
	"300": "多种选择",
	"301": "永久移动",
	"302": "临时移动",
	"303": "查看其它地址",
	"304": "未修改",
	"305": "使用代理",
	"306": "已经被废弃的HTTP状态码",
	"307": "临时重定向",
	"400": "客户端请求的语法错误",
	"401": "登陆过期,请重新登陆",
	"402": "保留,将来使用",
	"403": "拒绝执行此请求",
	"404": "当前接口不存在",
	"405": "请求被禁用",
	"406": "无法执行当前请求",
	"407": "请代理的身份认证",
	"408": "超时",
	"409": "服务器处理请求时发生了冲突",
	"410": "客户端请求的资源已经不存在",
	"411": "无法处理客户端发送的不带Content-Length的请求信息",
	"412": "客户端请求信息的先决条件错误",
	"413": "由于请求的实体过大",
	"414": "请求的URI过长",
	"415": "媒体格式无法处理",
	"416": "请求范围无效",
	"417": "无法满足Expect的请求头信息",
	"426": "账号密码错误",
	"500": "内部错误",
	"501": "接口无效",
	"502": "无效响应",
	"503": "系统维护中",
	"504": "系统维护中",
	"505": "不支持当前HTTP协议"
}

总结:可能小白有点不理解的地方,临时加一个截图有助于理解:新写的项目,没进行测试,测试后如果有问题我在更新一下。感谢大家看完。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值