Files
cashier-web/src/utils/request.ts

136 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import axios, { type InternalAxiosRequestConfig, type AxiosResponse } from "axios";
import qs from "qs";
import { useUserStoreHook } from "@/store/modules/user";
import { ResultEnum } from "@/enums/ResultEnum";
import { getToken } from "@/utils/auth";
import router from "@/router";
// 创建 axios 实例
const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 50000,
headers: { "Content-Type": "application/json;charset=utf-8", platformType: 'WEB' },
paramsSerializer: (params) => qs.stringify(params),
});
// 请求拦截器
service.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
const accessToken = getToken();
// 如果 Authorization 设置为 no-auth则不携带 Token用于登录、刷新 Token 等接口
if (config.headers.Authorization !== "no-auth" && accessToken) {
config.headers.token = accessToken;
} else {
delete config.headers.token;
}
config.headers.shopId = config.headers.shopId || useUserStoreHook().userInfo.id;
return config;
},
(error) => Promise.reject(error)
);
// 响应拦截器
service.interceptors.response.use(
(response: AxiosResponse) => {
// 如果响应是二进制流则直接返回用于下载文件、Excel 导出等
if (response.config.responseType === "blob") {
return response;
}
const { code, data, msg } = response.data;
if (data) {
// 处理后台返回分页相关数据为字符串类型时elementui组件警告
const kes = ['pageNumber', 'pageSize', 'totalPage', 'totalRow'];
const keys = Object.keys(data);
for (let i of kes) {
if (keys.includes(i)) {
data[i] = data[i] * 1;
}
}
}
if (code === ResultEnum.SUCCESS || code === undefined || code === null) {
return data ? data : response.data;
}
if (code === ResultEnum.ACCESS_TOKEN_INVALID) {
ElNotification({
title: "提示",
message: "您的会话已过期,请重新登录",
type: "info",
});
useUserStoreHook()
.clearUserData()
.then(() => {
router.push("/login");
});
return;
}
ElMessage.error(msg || "系统出错");
return Promise.reject(new Error(msg || "Error"));
},
async (error: any) => {
// 非 2xx 状态码处理 401、403、500 等
const { config, response } = error;
if (response) {
const { code, message } = response.data;
if (code === ResultEnum.ACCESS_TOKEN_INVALID) {
// Token 过期,刷新 Token
return handleTokenRefresh(config);
} else if (code === ResultEnum.REFRESH_TOKEN_INVALID) {
return Promise.reject(new Error(message || "Error"));
} else {
ElMessage.error(message || "系统出错");
}
}
return Promise.reject(error.message);
}
);
export default service;
// 刷新 Token 的锁
let isRefreshing = false;
// 因 Token 过期导致失败的请求队列
let requestsQueue: Array<() => void> = [];
// 刷新 Token 处理
async function handleTokenRefresh(config: InternalAxiosRequestConfig) {
return new Promise((resolve) => {
const requestCallback = () => {
config.headers.Authorization = getToken();
resolve(service(config));
};
requestsQueue.push(requestCallback);
if (!isRefreshing) {
isRefreshing = true;
// 刷新 Token
useUserStoreHook()
.refreshToken()
.then(() => {
// Token 刷新成功,执行请求队列
requestsQueue.forEach((callback) => callback());
requestsQueue = [];
})
.catch((error) => {
console.log("handleTokenRefresh error", error);
// Token 刷新失败,清除用户数据并跳转到登录
ElNotification({
title: "提示",
message: "您的会话已过期,请重新登录",
type: "info",
});
useUserStoreHook()
.clearUserData()
.then(() => {
router.push("/login");
});
})
.finally(() => {
isRefreshing = false;
});
}
});
}