144 lines
4.2 KiB
TypeScript
144 lines
4.2 KiB
TypeScript
import { useAccessStore, useUserStore } from '@vben/stores';
|
||
|
||
import { message as Message } from 'ant-design-vue';
|
||
|
||
import { postApiAppAccountRefreshToken } from '#/api-client';
|
||
import { $t } from '#/locales';
|
||
import { antdLocale } from '#/locales/index';
|
||
import { useAuthStore } from '#/store';
|
||
|
||
import { client } from '../api-client/services.gen';
|
||
|
||
client.setConfig({
|
||
baseURL: import.meta.env.DEV
|
||
? '/proxy/'
|
||
: import.meta.env.VITE_APP_API_ADDRESS,
|
||
timeout: 1000 * 60,
|
||
responseType: 'json',
|
||
throwOnError: true,
|
||
});
|
||
// 是否正在刷新token
|
||
let isRefreshing = false;
|
||
// 刷新token队列
|
||
let refreshTokenQueue: ((token: string) => void)[] = [];
|
||
client.instance.interceptors.request.use((request) => {
|
||
// 全局拦截请求发送前提交的参数
|
||
const userStore = useUserStore();
|
||
const accessStore = useAccessStore();
|
||
const token = accessStore.getAccessToken();
|
||
// 设置请求头
|
||
if (request.headers) {
|
||
request.headers.__tenant = userStore.tenant?.tenantId;
|
||
// todo vben5 没有提供统一获取当前语言的方式
|
||
request.headers['accept-language'] = antdLocale.value.locale;
|
||
}
|
||
|
||
// 如果token过期,则跳转到登录页面
|
||
if (
|
||
request.url !== undefined &&
|
||
request.url.includes('/api/app/account/login')
|
||
) {
|
||
return request;
|
||
}
|
||
|
||
// 设置请求头
|
||
if (request.headers) {
|
||
request.headers.Authorization = `Bearer ${token}`;
|
||
}
|
||
|
||
return request;
|
||
});
|
||
|
||
client.instance.interceptors.response.use(
|
||
(response) => {
|
||
return Promise.resolve(response);
|
||
},
|
||
async (error) => {
|
||
let message = error.message;
|
||
if (message === 'Network Error') {
|
||
message = $t('common.mesage500');
|
||
} else if (message.includes('timeout')) {
|
||
message = $t('common.timeOut');
|
||
} else
|
||
switch (error.status) {
|
||
case 400: {
|
||
message = error.response.data.error?.validationErrors[0].message;
|
||
break;
|
||
}
|
||
case 401: {
|
||
message = $t('common.mesage401');
|
||
const { config } = error;
|
||
const originalRequest = config;
|
||
if (isRefreshing) {
|
||
return new Promise((resolve) => {
|
||
refreshTokenQueue.push((token) => {
|
||
originalRequest.headers.Authorization = `Bearer ${token}`;
|
||
resolve(client.request(originalRequest));
|
||
});
|
||
});
|
||
} else {
|
||
isRefreshing = true;
|
||
try {
|
||
const newToken = await refreshTokenAsync();
|
||
// 处理队列中的请求
|
||
refreshTokenQueue.forEach((callback) => callback(newToken));
|
||
// 清空队列
|
||
refreshTokenQueue = [];
|
||
return client.request(originalRequest);
|
||
} catch (refreshError) {
|
||
// 如果刷新 token 失败,处理错误(如强制登出或跳转登录页面)
|
||
message = $t('common.mesage401');
|
||
refreshTokenQueue = [];
|
||
const authStore = useAuthStore();
|
||
authStore.logout();
|
||
console.error(refreshError);
|
||
} finally {
|
||
isRefreshing = false;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 403: {
|
||
message = $t('common.mesage403');
|
||
break;
|
||
}
|
||
case 500: {
|
||
message = error.response.data.error?.message;
|
||
break;
|
||
}
|
||
default: {
|
||
if (message.includes('Request failed with status code')) {
|
||
message = $t('common.mesage500');
|
||
}
|
||
}
|
||
}
|
||
Message.error(message);
|
||
throw error;
|
||
},
|
||
);
|
||
|
||
async function refreshTokenAsync(): Promise<string> {
|
||
try {
|
||
const userStore = useUserStore();
|
||
const accessStore = useAccessStore();
|
||
const refreshToken = accessStore.getRefreshToken();
|
||
if (!refreshToken) return '';
|
||
const res = await postApiAppAccountRefreshToken({
|
||
body: {
|
||
userId: userStore.userInfo?.id,
|
||
refreshToken,
|
||
},
|
||
});
|
||
if (res?.data?.success) {
|
||
accessStore.setAccessToken(res.data.token as string);
|
||
accessStore.setRefreshToken(res.data.refreshToken as string);
|
||
return res.data.token as string;
|
||
} else {
|
||
throw new Error('get refreshToken error');
|
||
}
|
||
} catch {
|
||
throw new Error($t('common.mesage401'));
|
||
}
|
||
}
|
||
export default client;
|