基础版,添加 loading
在请求响应拦截器里面添加 loading,这样就不需要给每一个请求添加 loading 了
这些代码都是 vue2 项目的,vue3 也通用,改一下 loading 和 message 就好了(主要是 element 的区别)
我这里最后没有合并代码,有的配置不适合写在一起,看自己项目的需要
import axios from 'axios';
import { Loading, Message } from 'element-ui';
const instance = axios.create({
baseURL: 'http://localhost:5500',
timeout: 30000,
});
let loadingInstance = null;
// 添加请求拦截器
instance.interceptors.request.use(
(config) => {
loadingInstance = Loading.service({
fullscreen: true,
text: '加载中...',
background: "black",
});
return config;
},
// 断网走这里
(error) => {
Message.error('请求错误:' + error.message);
return Promise.reject(error);
},
);
// 添加响应拦截器
instance.interceptors.response.use(
({ data }) => {
loadingInstance.close();
return data;
},
// !== 2xx 走这里
(error) => {
loadingInstance.close();
return Promise.reject(error.response);
},
);
export default instance
响应状态码配置
响应状态码配置,更好的给用户提示,这里只设计到响应,就只写了响应拦截
// 根据规范添加配置
const statusOption = [
{
code: "200",
state: "success",
description: "请求(或处理)成功",
},
{
code: "400",
state: "ParameterError",
description: "请求参数不完整或不正确",
},
{
code: "401",
state: "Unauthorized",
description: "访问请求未授权! 当前 SESSION 失效, 请重新登陆",
},
{
code: "403",
state: "Forbidden",
description: "您无权进行此操作,请求执行已拒绝",
},
{
code: "404",
state: "NotFound",
description: "找不到与请求匹配的 HTTP 资源",
},
{
code: "405",
state: "HttpMehtodError",
description: "HTTP请求类型不合法",
},
{
code: "406",
state: "HttpRequestError",
description: "HTTP请求不合法,请求参数可能被篡改",
},
{
code: "407",
state: "URLExpireError",
description: "该URL已经失效",
},
{
code: "500",
state: "Error",
description: "内部请求出错",
},
];
// 添加响应拦截器
instance.interceptors.response.use(
({ data }) => {
loadingInstance.close();
// 这里是请求成功的内部状态码
// 这个要和后端约定,我这里就默认除了 200 都有问题
// 这样就不用在请求接口出错的时候一个个 message 了
if (data.status !== 200) {
Message.error(data.message);
return Promise.reject(data);
}
return Promise.resolve(data);
},
(error) => {
let status = error.response.status;
if (status < 400) {
Message.warning(error.response.statusText);
} else {
let err = statusOption.find((item) => item.code == status);
Message.error(err ? err.description : "响应出错请联系管理员!");
}
loadingInstance.close();
return Promise.reject(error.response);
}
);
loading 串行、并行
串行 loading 闪屏、并行 loading 提前关闭
- 串行的情况是请求之间的依赖,请求 A 完成后立即开始请求 B,这样会导致 loading 闪屏
- 并行是两个请求同时请求,请求 A 的时间为 5s,请求 B 的时间为 3s,因为 loading 都是同一个实例,会导致请求 B 时提前关闭 loading,关闭两秒后又请求到了新的数据
import axios from "axios";
import { Loading, Message } from 'element-ui';
const instance = axios.create({
baseURL: "http://localhost:5500",
timeout: 30000,
});
// 处理并行
let loadingCount = 0;
// 处理串行
let loadingTimer = null;
function loadingClose() {
loadingCount--;
if (!loadingCount) {
// 延迟等待是否还有下一个请求
loadingTimer = setTimeout(() => {
loadingInstance.close();
loadingTimer = null;
}, 300);
}
}
function loadingOpen() {
loadingCount++;
// 如果有请求需要清除关闭
if (loadingTimer) {
clearTimeout(loadingTimer);
loadingTimer = null;
}
loadingInstance = Loading.service({
fullscreen: true,
text: "加载中...",
background: "black",
});
}
let loadingInstance = null;
// 添加请求拦截器
instance.interceptors.request.use(
(config) => {
loadingOpen();
return config;
},
(error) => {
Message.error("请求错误:" + error.message);
return Promise.reject(error);
}
);
// 添加响应拦截器
instance.interceptors.response.use(
({ data }) => {
loadingClose();
return data;
},
(error) => {
loadingClose();
return Promise.reject(error.response);
}
);
export default instance;
请求挂起
延迟请求发送
我这里的应用场景是 token,当我发现当前请求没有 token 时,先挂起当前请求然后获取 token,在添加上
import axios from "axios";
import { Loading, Message } from 'element-ui';
const instance = axios.create({
baseURL: "http://localhost:5500",
timeout: 30000,
});
// 获取 token 的方法,这里的请求不能使用封装的,不然请求一直没有 token 就会一直挂起
async function passParamsGetToken() {}
let loadingInstance = null;
// 添加请求拦截器
instance.interceptors.request.use(
// 这种用 async/await 也可以,更易读一些,原理都是等待请求的发送
(config) => {
if (!config.headers.Authorization) {
// 请求挂起
return new Promise(async (resolve, reject) => {
let token = await passParamsGetToken();
// 为当前请求添加 token
config.headers.Authorization = token;
// 为实例添加 token,这样下一个请求也会存在token
instance.defaults.headers.common["Authorization"] = token;
loadingInstance = Loading.service({
fullscreen: true,
text: "加载中...",
background: "black",
});
resolve(config);
});
} else {
loadingInstance = Loading.service({
fullscreen: true,
text: "加载中...",
background: "black",
});
return config;
}
},
(error) => {
Message.error("请求错误:" + error.message);
return Promise.reject(error);
}
);
// 添加响应拦截器
instance.interceptors.response.use(
({ data }) => {
loadingInstance.close();
return data;
},
(error) => {
loadingInstance.close();
return Promise.reject(error.response);
}
);
export default instance;
取消请求
重复请求需要取消,取消请求会走响应拦截器的 error,会和请求重试有冲突文章来源:https://www.toymoban.com/news/detail-496976.html
- 取消请求不是真正意义上的取消,请求已经发送,后端接收到了,只是前端不在响应了
- 使用表单类的操作,取消请求没用,顶多是获取列表的时候,前端少处理一次操作
import axios from "axios";
import { Loading, Message } from 'element-ui';
const requestMap = new Map();
function setRequestMap(config) {
requestMap.set(JSON.stringify(config), config);
}
function deleteRequestMap(config) {
let xLConfig = JSON.stringify(config);
let hasConfig = null;
if ((hasConfig = requestMap.get(xLConfig))) {
// 请求完成后在取消,不影响
hasConfig.controller.abort();
requestMap.delete(xLConfig);
}
}
// 设置控制器,需要先设置控制器,这样添加删除后的序列化字符才可以匹配
function setAbortController(config) {
const controller = new AbortController();
config.controller = controller;
config.signal = controller.signal;
}
const instance = axios.create({
baseURL: "http://localhost:5500",
timeout: 30000,
});
let loadingInstance = null;
// 添加请求拦截器
instance.interceptors.request.use(
(config) => {
setAbortController(config);
deleteRequestMap(config);
setRequestMap(config);
loadingInstance = Loading.service({
fullscreen: true,
text: "加载中...",
background: "black",
});
return config;
},
(error) => {
Message.error("请求错误:" + error.message);
return Promise.reject(error);
}
);
// 添加响应拦截器
instance.interceptors.response.use(
(response) => {
deleteRequestMap(response.config);
loadingInstance.close();
return response.data;
},
(error) => {
// 重复请求的取消,表示后面肯定有请求,则不需要关闭 loading
if (axios.isCancel(error)) {
// console.log("Request canceled", 123123);
// 其他异常的处理
} else {
deleteRequestMap(error.config);
loadingInstance.close();
}
return Promise.reject(error.response);
}
);
export default instance;
请求重试
请求失败需要重试文章来源地址https://www.toymoban.com/news/detail-496976.html
// utils/reuqest.js 中
import axios from "axios";
import { Loading, Message } from 'element-ui';
const instance = axios.create({
baseURL: "http://localhost:5500",
timeout: 30000,
retry: 3, // 最大重试次数为 3
retryDelay: 1000, // 重试时的延迟时间为 1 秒
});
let loadingInstance = null;
// 添加请求拦截器
instance.interceptors.request.use(
(config) => {
loadingInstance = Loading.service({
fullscreen: true,
text: config.retryCount ? "请求重试中..." : "加载中...", // 重试后改变 text 显示
background: "black",
});
return config;
},
(error) => {
Message.error("请求错误:" + error.message);
return Promise.reject(error);
}
);
// 添加响应拦截器
instance.interceptors.response.use(
({ data }) => {
loadingInstance.close();
return data;
},
(error) => {
loadingInstance.close();
const config = error.config;
// 没有重试的请求直接抛出
if (!config || !config.retry) {
return Promise.reject(error);
}
// 超过重试次数抛出
config.retryCount = config.retryCount || 0;
if (config.retryCount >= config.retry) {
// 因为每次请求的实例对象都不一样,所以为当前实例添加 retryCount,不会影响其他实例
return Promise.reject(error);
}
// 请求重试
config.retryCount += 1;
return new Promise((resolve) => {
setTimeout(() => {
resolve(instance(config));
}, config.retryDelay);
});
}
);
export default instance;
到了这里,关于vue2/3 axios 请求重试、取消请求、loading 串行并行等(分享)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!