基礎版,添加 loading
在請求響應攔截器里面添加 loading,這樣就不需要給每一個請求添加 loading 了
這些代碼都是 vue2 項目的,vue3 也通用,改一下 loading 和 message 就好了(主要是 element 的區(qū)別)
我這里最后沒有合并代碼,有的配置不適合寫在一起,看自己項目的需要
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;
},
// 斷網(wǎng)走這里
(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
響應狀態(tài)碼配置
響應狀態(tài)碼配置,更好的給用戶提示,這里只設計到響應,就只寫了響應攔截
// 根據(jù)規(guī)范添加配置
const statusOption = [
{
code: "200",
state: "success",
description: "請求(或處理)成功",
},
{
code: "400",
state: "ParameterError",
description: "請求參數(shù)不完整或不正確",
},
{
code: "401",
state: "Unauthorized",
description: "訪問請求未授權! 當前 SESSION 失效, 請重新登陸",
},
{
code: "403",
state: "Forbidden",
description: "您無權進行此操作,請求執(zhí)行已拒絕",
},
{
code: "404",
state: "NotFound",
description: "找不到與請求匹配的 HTTP 資源",
},
{
code: "405",
state: "HttpMehtodError",
description: "HTTP請求類型不合法",
},
{
code: "406",
state: "HttpRequestError",
description: "HTTP請求不合法,請求參數(shù)可能被篡改",
},
{
code: "407",
state: "URLExpireError",
description: "該URL已經(jīng)失效",
},
{
code: "500",
state: "Error",
description: "內部請求出錯",
},
];
// 添加響應攔截器
instance.interceptors.response.use(
({ data }) => {
loadingInstance.close();
// 這里是請求成功的內部狀態(tài)碼
// 這個要和后端約定,我這里就默認除了 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 : "響應出錯請聯(lián)系管理員!");
}
loadingInstance.close();
return Promise.reject(error.response);
}
);
loading 串行、并行
串行 loading 閃屏、并行 loading 提前關閉
- 串行的情況是請求之間的依賴,請求 A 完成后立即開始請求 B,這樣會導致 loading 閃屏
- 并行是兩個請求同時請求,請求 A 的時間為 5s,請求 B 的時間為 3s,因為 loading 都是同一個實例,會導致請求 B 時提前關閉 loading,關閉兩秒后又請求到了新的數(shù)據(jù)
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;
請求掛起
延遲請求發(fā)送
我這里的應用場景是 token,當我發(fā)現(xiàn)當前請求沒有 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 也可以,更易讀一些,原理都是等待請求的發(fā)送
(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,會和請求重試有沖突文章來源:http://www.zghlxwxcb.cn/news/detail-496976.html
- 取消請求不是真正意義上的取消,請求已經(jīng)發(fā)送,后端接收到了,只是前端不在響應了
- 使用表單類的操作,取消請求沒用,頂多是獲取列表的時候,前端少處理一次操作
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;
請求重試
請求失敗需要重試文章來源地址http://www.zghlxwxcb.cn/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, // 最大重試次數(shù)為 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);
}
// 超過重試次數(shù)拋出
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模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!