可以查看axios的中文文档,地址如下
https://www.axios-http.cn/
为什么要对axios进行二次封装:
由于自带的axios不能满足我们的需求,需要对其进行二次封装,方便程序员使用
// 引入axiosimport axios from 'axios'// @ts-ignoreimport { 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)=>{//获取tokenconst 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.statusswitch(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对应的值cancelconst 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); // 删除keyaddRequestKey(config); // 添加keyreturn config;});request.interceptors.response.use((response) => {removeRequestKey(response.config); // 删除keyconst 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); // 删除keylet 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的二次封装最终版```typescriptimport 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); // 删除keyaddRequestKey(config); // 添加keyreturn config;});request.interceptors.response.use((response) => {removeRequestKey(response.config); // 删除keyconst 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); // 删除keylet 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
