最近,参考了下以前的项目,每个项目的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协议"
}
总结:可能小白有点不理解的地方,临时加一个截图有助于理解:新写的项目,没进行测试,测试后如果有问题我在更新一下。感谢大家看完。