可以查看axios的中文文档,地址如下
https://www.axios-http.cn/
为什么要对axios进行二次封装:
由于自带的axios不能满足我们的需求,需要对其进行二次封装,方便程序员使用
// 引入axios
import axios from 'axios'
// @ts-ignore
import { ElMessage } from "element-plus";
import (GET_TOKEN) from './token.ts'
// 第一步:利用axios对象的create方法,去创建axios实例(其他的配置:基础路径、超时时间)
const requeset = axios.create({
// 基础路径
baseURL: import.meta.env.VITE_APP_BASE_API,//后期可以换成自己的项目地址
// 设置超时时间
timeout: 5000,
})
// // 第二步:给request实例添加请求拦截器
requeset.interceptors.request.use((config)=>{
//获取token
const token = GET_TOKEN()
if(token){
config.header.token = token
}
// 返回配置对象
return config;
})
// 第三步:给request实例添加响应拦截器
requeset.interceptors.response.use((response)=>{
// 成功的回调
// 简化数据
return response.data
},
(error)=>{
// 失败的回调:处理http网络错误
// 定义一个变量,存储网络错误信息
let message = '';
// http状态码
let status = error.response.status
switch(status){
case 401:
message = 'TOKEN过期';
break;
case 403:
message = '无权访问';
break;
case 404:
message = '请求地址错误';
break;
case 500:
message = '服务器出现问题';
break;
default:
message = '网络出现错误';
break;
}
// 提示错误信息
ElMessage({
type:'error',
message
})
return Promise.reject(error);
}
)
// 对外暴露
export default requeset;
而在开发阶段,我们可以使用上面对axios的二次封装来发送请求获取数据,在生产环境中为了提高用户的体验,减小网络带宽,减小服务器压力,我们会在发请求前对用户的地址进行判断,对网络的错误进行统一的错误提示
1.统一错误处理
import axios from "axios";
import { ElMessage } from "element-plus";
import { useUserStore } from "../../store/modules/user";
// 功能失败的错误原因
export const authErrMessage: any = {
10031: "登录失效,需要重新登录",
10032: "您太久没登录,请重新登录~",
10033: "账户未绑定角色,请联系管理员绑定角色",
10034: "该用户未注册,请联系管理员注册用户",
10035: "code 无法获取对应第三方平台用户",
10036: "该账户未关联员工,请联系管理员做关联",
10037: "账号已无效",
10038: "账号未找到",
};
// 请求失败的错误原因
export const networkErrMessage: any = {
400: "错误的请求",
401: "未授权,请重新登录",
403: "拒绝访问",
404: "未找到该资源",
405: "请求方法未允许",
408: "请求超时",
500: "服务器端出错",
502: "网络错误",
503: "服务不可用",
504: "网络超时",
505: "http版本不支持该请求",
};
const request = axios.create({
// 需要在 .env.* 文件中定义环境变量才能使用
baseURL: import.meta.env.VITE_BASE_URL,
headers: {},
timeout: 20000,
});
request.interceptors.request.use((config) => {
const token = useUserStore().token;
if (token) {
config.headers.token = token;
}
return config;
});
request.interceptors.response.use(
(response) => {
const code = response.data.code;
if (code === 20000) {
return response.data;
} else {
let errMessage = authErrMessage[code];
if (errMessage) {
// 功能出错,需要特殊处理,比如要退出登录等
// useUserStore().logout();
} else {
errMessage = response.data.message;
}
ElMessage.error(errMessage);
return Promise.reject(errMessage);
}
},
(error) => {
let errMessage = "未知错误,请联系管理员解决";
if (error.response) {
// error.response有值,说明服务器有响应,响应结果是错误的,要根据响应状态码error.response.status来提示错误
errMessage = networkErrMessage[error.response.status];
} else {
// error.response没有值,说明服务器没有响应,请求在客户端就失败了,要根据浏览器提示的错误信息来处理
if (error.message.indexOf("timeout") > -1) {
// 请求超时
errMessage = "当前网络环境不稳定,请切换4/5G网络或WIFI网络试试";
} else if (error.message.indexOf("Network") > -1) {
// 断网了
errMessage = "没有检测到网络,请打开网络链接试试";
} else if (error.message.indexOf("canceled") > -1) {
errMessage = "请求取消了";
}
}
ElMessage.error(errMessage);
return Promise.reject(errMessage);
}
);
export default request;
2.取消重复请求
每个请求根据请求的配置项生成一个相应key(相同的请求生成的key相同,不同请求生成的key不同)
1.生成key
// 所有请求列表容器
//每个请求生成的key及key对应的值cancel
const requestListMap = new Map();
/**
* 每一个请求生成一个key
* @param config 请求配置对象
* @returns 唯一的key
*/
function getRequestKey(config: AxiosRequestConfig) {
let { url, method, params = {}, data = {} } = config;
return [url, method, JSON.stringify(params), JSON.stringify(data)].join("&");
}
删除key
/**
* 删除请求key
* @param config
*/
function removeRequestKey(config: AxiosRequestConfig) {
const requestKey = getRequestKey(config);
if (requestListMap.has(requestKey)) {
const cancel = requestListMap.get(requestKey);
cancel(); // 取消请求
requestListMap.delete(requestKey);
}
}
添加key
const CancelToken = axios.CancelToken;
/**
* 添加请求key
* @param config
*/
function addRequestKey(config: AxiosRequestConfig) {
const requestKey = getRequestKey(config);
config.cancelToken = new CancelToken((cancel) => {
if (!requestListMap.has(requestKey)) {
requestListMap.set(requestKey, cancel);
}
});
}
请求完成,在响应拦截器中需要将当前请求给删除
import axios from "axios";
import type { AxiosRequestConfig } from "axios";
import { ElMessage } from "element-plus";
import { useUserStore } from "../store/modules/user";
// 功能失败的错误原因
export const authErrMessage: any = {
10031: "登录失效,需要重新登录",
10032: "您太久没登录,请重新登录~",
10033: "账户未绑定角色,请联系管理员绑定角色",
10034: "该用户未注册,请联系管理员注册用户",
10035: "code 无法获取对应第三方平台用户",
10036: "该账户未关联员工,请联系管理员做关联",
10037: "账号已无效",
10038: "账号未找到",
};
// 请求失败的错误原因
export const networkErrMessage: any = {
400: "错误的请求",
401: "未授权,请重新登录",
403: "拒绝访问",
404: "未找到该资源",
405: "请求方法未允许",
408: "请求超时",
500: "服务器端出错",
502: "网络错误",
503: "服务不可用",
504: "网络超时",
505: "http版本不支持该请求",
};
// 所有请求列表容器
const requestListMap = new Map();
/**
* 每一个请求生成一个唯一的key
* @param config 请求配置对象
* @returns 唯一的key
*/
function getRequestKey(config: AxiosRequestConfig) {
const { url, method, params = {}, data = {} } = config;
return [url, method, JSON.stringify(params), JSON.stringify(data)].join("&");
}
const CancelToken = axios.CancelToken;
/**
* 添加请求key
* @param config
*/
function addRequestKey(config: AxiosRequestConfig) {
const requestKey = getRequestKey(config);
config.cancelToken = new CancelToken((cancel) => {
if (!requestListMap.has(requestKey)) {
requestListMap.set(requestKey, cancel);
}
});
}
/**
* 删除请求key
* @param config
*/
function removeRequestKey(config: AxiosRequestConfig) {
const requestKey = getRequestKey(config);
if (requestListMap.has(requestKey)) {
const cancel = requestListMap.get(requestKey);
cancel();
requestListMap.delete(requestKey);
}
}
const request = axios.create({
// 需要在 .env.* 文件中定义环境变量才能使用
baseURL: import.meta.env.VITE_BASE_URL,
headers: {},
timeout: 20000,
});
request.interceptors.request.use((config) => {
const token = useUserStore().token;
if (token) {
config.headers.token = token;
}
removeRequestKey(config); // 删除key
addRequestKey(config); // 添加key
return config;
});
request.interceptors.response.use(
(response) => {
removeRequestKey(response.config); // 删除key
const code = response.data.code;
if (code === 20000) {
return response.data;
} else {
let errMessage = authErrMessage[code];
if (errMessage) {
// 功能出错,需要特殊处理,比如要退出登录等
// useUserStore().logout();
} else {
errMessage = response.data.message;
}
ElMessage.error(errMessage);
return Promise.reject(errMessage);
}
},
(error) => {
error.config && removeRequestKey(error.config); // 删除key
let errMessage = "未知错误,请联系管理员解决";
if (error.response) {
// error.response有值,说明服务器有响应,响应结果是错误的,要根据响应状态码error.response.status来提示错误
errMessage = networkErrMessage[error.response.status];
} else {
// error.response没有值,说明服务器没有响应,请求在客户端就失败了,要根据浏览器提示的错误信息来处理
if (error.message.indexOf("timeout") > -1) {
// 请求超时
errMessage = "当前网络环境不稳定,请切换4/5G网络或WIFI网络试试";
} else if (error.message.indexOf("Network") > -1) {
// 断网了
errMessage = "没有检测到网络,请打开网络链接试试";
} else if (error.message.indexOf("canceled") > -1) {
errMessage = "请求取消了";
}
}
ElMessage.error(errMessage);
return Promise.reject(errMessage);
}
);
export default request;
取消上一个页面的请求
- 存储请求时,需要将取消请求的方法和当前路由路径一起储存
- 当路由跳转时,判断请求列表中的请求地址和要去的路由地址是否时同一个,如果不是,就要取消 ```typescript import axios from “axios”; import type { AxiosRequestConfig } from “axios”; import { ElMessage } from “element-plus”; import { useUserStore } from “../store/modules/user”;
// 功能失败的错误原因 export const authErrMessage: any = { 10031: “登录失效,需要重新登录”, 10032: “您太久没登录,请重新登录~”, 10033: “账户未绑定角色,请联系管理员绑定角色”, 10034: “该用户未注册,请联系管理员注册用户”, 10035: “code 无法获取对应第三方平台用户”, 10036: “该账户未关联员工,请联系管理员做关联”, 10037: “账号已无效”, 10038: “账号未找到”, };
// 请求失败的错误原因 export const networkErrMessage: any = { 400: “错误的请求”, 401: “未授权,请重新登录”, 403: “拒绝访问”, 404: “未找到该资源”, 405: “请求方法未允许”, 408: “请求超时”, 500: “服务器端出错”, 502: “网络错误”, 503: “服务不可用”, 504: “网络超时”, 505: “http版本不支持该请求”, };
// 所有请求列表容器 const requestListMap = new Map();
/**
- 每一个请求生成一个唯一的key
- @param config 请求配置对象
- @returns 唯一的key */ function getRequestKey(config: AxiosRequestConfig) { const { url, method, params = {}, data = {} } = config; return [url, method, JSON.stringify(params), JSON.stringify(data)].join(“&”); }
const CancelToken = axios.CancelToken;
/**
- 添加请求key
- @param config
*/
function addRequestKey(config: AxiosRequestConfig) {
const requestKey = getRequestKey(config);
config.cancelToken = new CancelToken((cancel) => {
if (!requestListMap.has(requestKey)) {
requestListMap.set(requestKey, {
}); } }); }cancel,
pathname: window.location.pathname,
/**
- 删除请求key
- @param config */ function removeRequestKey(config: AxiosRequestConfig) { const requestKey = getRequestKey(config); if (requestListMap.has(requestKey)) { const { cancel } = requestListMap.get(requestKey); cancel(); requestListMap.delete(requestKey); } }
const request = axios.create({ // 需要在 .env.* 文件中定义环境变量才能使用 baseURL: import.meta.env.VITE_BASE_URL, headers: {}, timeout: 20000, });
request.interceptors.request.use((config) => { const token = useUserStore().token; if (token) { config.headers.token = token; } removeRequestKey(config); // 删除key addRequestKey(config); // 添加key return config; });
request.interceptors.response.use( (response) => { removeRequestKey(response.config); // 删除key const code = response.data.code; if (code === 20000) { return response.data; } else { let errMessage = authErrMessage[code]; if (errMessage) { // 功能出错,需要特殊处理,比如要退出登录等 // useUserStore().logout(); } else { errMessage = response.data.message; } ElMessage.error(errMessage); return Promise.reject(errMessage); } }, (error) => { error.config && removeRequestKey(error.config); // 删除key let errMessage = “未知错误,请联系管理员解决”; if (error.response) { // error.response有值,说明服务器有响应,响应结果是错误的,要根据响应状态码error.response.status来提示错误 errMessage = networkErrMessage[error.response.status]; } else { // error.response没有值,说明服务器没有响应,请求在客户端就失败了,要根据浏览器提示的错误信息来处理 if (error.message.indexOf(“timeout”) > -1) { // 请求超时 errMessage = “当前网络环境不稳定,请切换4/5G网络或WIFI网络试试”; } else if (error.message.indexOf(“Network”) > -1) { // 断网了 errMessage = “没有检测到网络,请打开网络链接试试”; } else if (error.message.indexOf(“canceled”) > -1) { errMessage = “请求取消了”; } } ElMessage.error(errMessage); return Promise.reject(errMessage); } );
export { requestListMap };
export default request;
<a name="lGn8D"></a>
## Axios的二次封装最终版
```typescript
import axios from "axios";
import type { AxiosRequestConfig } from "axios";
import { ElMessage } from "element-plus";
import { useUserStore } from "../store/modules/user";
// 功能失败的错误原因
export const authErrMessage: any = {
10031: "登录失效,需要重新登录",
10032: "您太久没登录,请重新登录~",
10033: "账户未绑定角色,请联系管理员绑定角色",
10034: "该用户未注册,请联系管理员注册用户",
10035: "code 无法获取对应第三方平台用户",
10036: "该账户未关联员工,请联系管理员做关联",
10037: "账号已无效",
10038: "账号未找到",
};
// 请求失败的错误原因
export const networkErrMessage: any = {
400: "错误的请求",
401: "未授权,请重新登录",
403: "拒绝访问",
404: "未找到该资源",
405: "请求方法未允许",
408: "请求超时",
500: "服务器端出错",
502: "网络错误",
503: "服务不可用",
504: "网络超时",
505: "http版本不支持该请求",
};
// 所有请求列表容器
const requestListMap = new Map();
/**
* 每一个请求生成一个唯一的key
* @param config 请求配置对象
* @returns 唯一的key
*/
function getRequestKey(config: AxiosRequestConfig) {
const { url, method, params = {}, data = {} } = config;
return [url, method, JSON.stringify(params), JSON.stringify(data)].join("&");
}
const CancelToken = axios.CancelToken;
/**
* 添加请求key
* @param config
*/
function addRequestKey(config: AxiosRequestConfig) {
const requestKey = getRequestKey(config);
config.cancelToken = new CancelToken((cancel) => {
if (!requestListMap.has(requestKey)) {
requestListMap.set(requestKey, {
cancel,
pathname: window.location.pathname,
});
}
});
}
/**
* 删除请求key
* @param config
*/
function removeRequestKey(config: AxiosRequestConfig) {
const requestKey = getRequestKey(config);
if (requestListMap.has(requestKey)) {
const { cancel } = requestListMap.get(requestKey);
cancel();
requestListMap.delete(requestKey);
}
}
const request = axios.create({
// 需要在 .env.* 文件中定义环境变量才能使用
baseURL: import.meta.env.VITE_BASE_URL,
headers: {},
timeout: 20000,
});
request.interceptors.request.use((config) => {
const token = useUserStore().token;
if (token) {
config.headers.token = token;
}
removeRequestKey(config); // 删除key
addRequestKey(config); // 添加key
return config;
});
request.interceptors.response.use(
(response) => {
removeRequestKey(response.config); // 删除key
const code = response.data.code;
if (code === 20000) {
return response.data;
} else {
let errMessage = authErrMessage[code];
if (errMessage) {
// 功能出错,需要特殊处理,比如要退出登录等
// useUserStore().logout();
} else {
errMessage = response.data.message;
}
ElMessage.error(errMessage);
return Promise.reject(errMessage);
}
},
(error) => {
error.config && removeRequestKey(error.config); // 删除key
let errMessage = "未知错误,请联系管理员解决";
if (error.response) {
// error.response有值,说明服务器有响应,响应结果是错误的,要根据响应状态码error.response.status来提示错误
errMessage = networkErrMessage[error.response.status];
} else {
// error.response没有值,说明服务器没有响应,请求在客户端就失败了,要根据浏览器提示的错误信息来处理
if (error.message.indexOf("timeout") > -1) {
// 请求超时
errMessage = "当前网络环境不稳定,请切换4/5G网络或WIFI网络试试";
} else if (error.message.indexOf("Network") > -1) {
// 断网了
errMessage = "没有检测到网络,请打开网络链接试试";
} else if (error.message.indexOf("canceled") > -1) {
errMessage = "请求取消了";
}
}
ElMessage.error(errMessage);
return Promise.reject(errMessage);
}
);
export { requestListMap };
export default request;
开发环境的判断,需要安装第三方包
pnpm i @type/node