refactor: 登录超时逻辑

This commit is contained in:
dap
2025-07-04 15:41:09 +08:00
parent 7535bd6096
commit 29dd4ce7f7
4 changed files with 91 additions and 42 deletions

View File

@@ -1,3 +1,9 @@
import { $t } from '@vben/locales';
import { message } from 'ant-design-vue';
import { useAuthStore } from '#/store';
import { requestClient } from './request';
/**
@@ -26,3 +32,35 @@ export function commonExport(url: string, data: Record<string, any>) {
responseType: 'blob',
});
}
/**
* 定义一个401专用异常 用于可能会用到的区分场景?
*/
export class UnauthorizedException extends Error {}
/**
* 是否已经处在登出过程中了 一个标志位
* 主要是防止一个页面会请求多个api 都401 会导致登出执行多次
*/
let isLogoutProcessing = false;
/**
* 登出逻辑 两个地方用到 提取出来
* @throws UnauthorizedException 抛出特定的异常
*/
export function handleUnauthorizedLogout() {
const timeoutMsg = $t('http.loginTimeout');
// 已经在登出过程中 不再执行
if (isLogoutProcessing) {
throw new UnauthorizedException(timeoutMsg);
}
isLogoutProcessing = true;
const userStore = useAuthStore();
userStore.logout().finally(() => {
message.error(timeoutMsg);
isLogoutProcessing = false;
});
// 不再执行下面逻辑
throw new UnauthorizedException(timeoutMsg);
}

View File

@@ -4,6 +4,7 @@
import type { HttpResponse } from '@vben/request';
import { BUSINESS_SUCCESS_CODE, UNAUTHORIZED_CODE } from '@vben/constants';
import { useAppConfig } from '@vben/hooks';
import { $t } from '@vben/locales';
import { preferences } from '@vben/preferences';
@@ -28,22 +29,13 @@ import {
} from '#/utils/encryption/crypto';
import * as encryptUtil from '#/utils/encryption/jsencrypt';
import { handleUnauthorizedLogout } from './helper';
const { apiURL, clientId, enableEncrypt } = useAppConfig(
import.meta.env,
import.meta.env.PROD,
);
/**
* 是否已经处在登出过程中了 一个标志位
* 主要是防止一个页面会请求多个api 都401 会导致登出执行多次
*/
let isLogoutProcessing = false;
/**
* 定义一个401专用异常 用于可能会用到的区分场景?
*/
export class UnauthorizedException extends Error {}
function createRequestClient(baseURL: string) {
const client = new RequestClient({
// 后端地址
@@ -173,21 +165,38 @@ function createRequestClient(baseURL: string) {
// 不进行任何处理,直接返回
// 用于页面代码可能需要直接获取codedatamessage这些信息时开启
if (!isTransformResponse) {
/**
* 需要判断下载二进制的情况 正常是返回二进制 报错会返回json
* 当type为blob且content-type为application/json时 则判断已经下载出错
*/
if (
response.config.responseType === 'blob' &&
response.headers['content-type']?.includes?.('application/json')
) {
// 这时候的data为blob类型
const blob = response.data as unknown as Blob;
// 拿到字符串转json对象
response.data = JSON.parse(await blob.text());
// 然后按正常逻辑执行下面的代码(判断业务状态码)
// json数据的判断
if (response.headers['content-type']?.includes?.('application/json')) {
/**
* 需要判断是否登录超时/401
* 执行登出操作
*/
const resp = response.data as unknown as HttpResponse;
// 抛出异常 不再执行
if (
typeof resp === 'object' &&
Reflect.has(resp, 'code') &&
resp.code === UNAUTHORIZED_CODE
) {
handleUnauthorizedLogout();
}
/**
* 需要判断下载二进制的情况 正常是返回二进制 报错会返回json
* 当type为blob且content-type为application/json时 则判断已经下载出错
*/
if (response.config.responseType === 'blob') {
// 这时候的data为blob类型
const blob = response.data as unknown as Blob;
// 拿到字符串转json对象
response.data = JSON.parse(await blob.text());
// 然后按正常逻辑执行下面的代码(判断业务状态码)
} else {
// 其他类型数据 直接返回
return response.data;
}
} else {
// 其他情况 直接返回
// 非json数据 直接返回 不做校验
return response.data;
}
}
@@ -200,8 +209,10 @@ function createRequestClient(baseURL: string) {
// 后端并没有采用严格的{code, msg, data}模式
const { code, data, msg, ...other } = axiosResponseData;
// 业务状态码为200则请求成功
const hasSuccess = Reflect.has(axiosResponseData, 'code') && code === 200;
// 业务状态码为200 则请求成功
const hasSuccess =
Reflect.has(axiosResponseData, 'code') &&
code === BUSINESS_SUCCESS_CODE;
if (hasSuccess) {
let successMsg = msg;
@@ -230,20 +241,10 @@ function createRequestClient(baseURL: string) {
// 如果不希望中断当前请求请return数据否则直接抛出异常即可
let timeoutMsg = '';
switch (code) {
case 401: {
// 已经在登出过程中 不再执行
if (isLogoutProcessing) {
throw new UnauthorizedException(timeoutMsg);
}
isLogoutProcessing = true;
const _msg = $t('http.loginTimeout');
const userStore = useAuthStore();
userStore.logout().finally(() => {
message.error(_msg);
isLogoutProcessing = false;
});
// 不再执行下面逻辑
throw new UnauthorizedException(_msg);
// 登录超时
case UNAUTHORIZED_CODE: {
handleUnauthorizedLogout();
break;
}
default: {
if (msg) {

View File

@@ -1,4 +1,4 @@
import { UnauthorizedException } from '#/api/request';
import { UnauthorizedException } from '#/api/helper';
import { dictDataInfo } from '#/api/system/dict/dict-data';
import { useDictStore } from '#/store/dict';

View File

@@ -26,3 +26,13 @@ export const SUPPORT_LANGUAGES: LanguageOption[] = [
* 默认租户ID
*/
export const DEFAULT_TENANT_ID = '000000';
/**
* 业务成功 状态码
*/
export const BUSINESS_SUCCESS_CODE = 200;
/**
* 未授权 状态码(登录超时)
*/
export const UNAUTHORIZED_CODE = 401;