1. 安装axios
npm i axios --save
yarn add axios --save
2.定义所需要的接口
export type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
export type ResponseType = 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream';
export interface AxiosRequest {
baseURL?: string;
url: string;
data?: any;
params?: any;
method?: Method;
show?: any,
headers?: any;
timeout?: number;
responseType?: ResponseType;
}
export interface AxiosResponse {
data: any;
headers: any;
request?: any;
status: number;
statusText: string;
config: AxiosRequest;
}
export interface CustomResponse {
readonly status: boolean;
readonly message: string;
data: any;
origin?: any;
}
3.创建axios 实例,并进行拦截器配置
import axios, { AxiosRequestConfig, Method } from 'axios';
import { Toast } from 'vant';
// 定义接口
interface PendingType {
url?: string;
method?: Method;
params: any;
data: any;
cancel: Function;
}
// 取消重复请求
const pending: Array<PendingType> = [];
const CancelToken = axios.CancelToken;
// axios 实例
const instance = axios.create({
timeout: 10000,
responseType: 'json'
});
// 移除重复请求
const removePending = (config: AxiosRequestConfig) => {
for (const key in pending) {
const item: number = +key;
const list: PendingType = pending[key];
// 当前请求在数组中存在时执行函数体
if (list.url === config.url && list.method === config.method && JSON.stringify(list.params) === JSON.stringify(config.params) && JSON.stringify(list.data) === JSON.stringify(config.data)) {
// 执行取消操作
list.cancel('操作太频繁,请稍后再试');
// 从数组中移除记录
if(pending.length > 1){
pending.splice(item, 1)
}
}
}
};
// 添加请求拦截器
instance.interceptors.request.use(
request => {
Toast({
message: '加载中',
forbidClick: true,
});
console.log(request,'111')
removePending(request);
request.cancelToken = new CancelToken((c) => {
pending.push({ url: request.url, method: request.method, params: request.params, data:request.data, cancel: c, });
});
return request;
},
error => {
return Promise.reject(error);
}
);
// 添加响应拦截器
instance.interceptors.response.use(
response => {
Toast.clear();
removePending(response.config);
const errorCode = response?.data?.errorCode;
switch (errorCode) {
case '401':
// 根据errorCode,对业务做异常处理(和后端约定)
break;
default:
break;
}
return response;
},
error => {
Toast.clear();
const response = error.response;
// 根据返回的http状态码做不同的处理
switch (response?.status) {
case 400:
// 页面找不到
break;
case 401:
// token失效
break;
case 403:
// 没有权限
break;
case 500:
// 服务端错误
break;
case 503:
// 服务端错误
break;
default:
// 接口异常
break;
}
// 超时重新请求
const config = error.config;
// 全局的请求次数,请求的间隙
const [RETRY_COUNT, RETRY_DELAY] = [0, 1000];
if (config && RETRY_COUNT) {
// 设置用于跟踪重试计数的变量
config.__retryCount = config.__retryCount || 0;
// 检查是否已经把重试的总数用完
if (config.__retryCount >= RETRY_COUNT) {
return Promise.reject(response || { message: error.message });
}
// 增加重试计数
config.__retryCount++;
// 创造新的Promise来处理指数后退
const backoff = new Promise<void>((resolve) => {
setTimeout(() => {
resolve();
}, RETRY_DELAY || 1);
});
// instance重试请求的Promise
return backoff.then(() => {
return instance(config);
});
}
return Promise.reject(response || { message: error.message });
}
);
export default instance;
4.封装axios的基类
/**
* axios基础构建
* @date 2021-02-04
*/
import { HOST } from './config';
import instance from './intercept';
import { AxiosRequest, CustomResponse } from './types';
import { Decrypt, Encrypt } from '../until/until';
import { Toast } from 'vant';
// 外部传入的baseUrl
const token = window.localStorage.getItem("userInfo")? JSON.parse(Decrypt(window.localStorage.getItem("userInfo"))).token: "",
reqURL = HOST,
header: object = {
'Content-Type': 'application/json;charset=UTF-8',
'X-Requested-With': 'XMLHttpRequest',
token: token
};
class Abstract {
private apiAxios({ baseURL = reqURL, headers = header, method, url, data, params, responseType, show }: AxiosRequest): Promise<CustomResponse> {
return new Promise((resolve, reject) => {
instance({
baseURL,
headers,
method,
url,
params,
data,
responseType,
}).then((res) => {
if (res.headers.token) {
resetToken(res.headers);
}
// 200:服务端业务处理正常结束
if (res.status === 200) {
if (res.data.success) {
resolve({ status: true, message: 'success', data: res.data?.data, origin: res.data });
} else {
Toast.fail({ message: res.data?.message });
resolve({ status: false, message: res.data?.message, data: res.data?.data, origin: res.data });
}
} else {
resolve({ status: false, message: res.data?.message, data: null });
}
}).catch((err) => {
const message = err?.data?.message || err?.message;
Toast.fail({ message });
reject({ status: false, message, data: null });
});
});
}
/**
* GET类型的网络请求
*/
protected getRequest({ url, data, params, responseType, show }: AxiosRequest) {
return this.apiAxios({ method: 'GET', url, data, params, responseType,show });
}
/**
* POST类型的网络请求
*/
protected postRequest({ url, data, params, responseType, show }: AxiosRequest) {
return this.apiAxios({ method: 'POST', url, data, params, responseType, show });
}
/**
* PUT类型的网络请求
*/
protected putRequest({ url, data, params, responseType }: AxiosRequest) {
return this.apiAxios({ method: 'PUT', url, data, params, responseType });
}
/**
* DELETE类型的网络请求
*/
protected deleteRequest({ url, data, params, responseType }: AxiosRequest) {
return this.apiAxios({ method: 'DELETE', url, data, params, responseType });
}
}
export default Abstract;
function resetToken(header:any) {
let userInfo = JSON.parse(Decrypt(window.localStorage.getItem("userInfo")));
delete userInfo["token"];
userInfo["token"] = header.token;
window.localStorage.setItem("userInfo", Encrypt(JSON.stringify(userInfo)));
}
5.对访问服务器进行配置
6.定义具体的业务请求
/**
* 基础数据 API 集合类
* 集成Abstract
* @date 2021-02-03
*/
import Abstract from '../axios/abstract';
class Basic extends Abstract {
loginCode(params:any) {
const url = "/shop/h5/open/user/sms/sign/code";
return new Promise(resolve => {
this.postRequest({ url, params }).then(res => {
resolve(res);
});
});
}
login(params:any) {
const url = "/shop/h5/open/user/sms/share/sale/login";
return new Promise(resolve => {
this.postRequest({ url, params }).then(res => {
resolve(res);
});
});
}
}
// 单列模式返回对象
let login;
export default (() => {
if (login) return login;
login = new Basic();
return login;
})();
项目文件配置路径