Files
cn-rdms-web/src/service/request/index.ts

174 lines
6.2 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 type { AxiosResponse } from 'axios';
import { BACKEND_ERROR_CODE, createFlatRequest, createRequest } from '@sa/axios';
import { useAuthStore } from '@/store/modules/auth';
import { localStg } from '@/utils/storage';
import { getServiceBaseURL } from '@/utils/service';
import { $t } from '@/locales';
import { applyApiEncrypt } from './api-encrypt';
import { getAuthorization, handleExpiredRequest, showErrorMsg } from './shared';
import { withDedupe } from './dedupe';
import type { RequestInstanceState } from './type';
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
const { baseURL, otherBaseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);
export const request = withDedupe(
createFlatRequest(
{
baseURL,
headers: {
apifoxToken: 'XL299LiMEDZ0H5h3A29PxwQXdMJqWyY2'
}
},
{
defaultState: {
errMsgStack: [],
refreshTokenPromise: null
} as RequestInstanceState,
transform(response: AxiosResponse<App.Service.Response<any>>) {
return response.data.data;
},
async onRequest(config) {
const Authorization = getAuthorization();
Object.assign(config.headers, { Authorization });
applyApiEncrypt(config);
return config;
},
isBackendSuccess(response) {
// 当后端返回码为 "0"(默认)时,表示请求成功
// 如需调整该逻辑,可修改 `.env` 中的 `VITE_SERVICE_SUCCESS_CODE`
return String(response.data.code) === import.meta.env.VITE_SERVICE_SUCCESS_CODE;
},
async onBackendFail(response, instance) {
const authStore = useAuthStore();
const responseCode = String(response.data.code);
function handleLogout() {
authStore.resetStore();
}
function logoutAndCleanup() {
handleLogout();
window.removeEventListener('beforeunload', handleLogout);
request.state.errMsgStack = request.state.errMsgStack.filter(msg => msg !== response.data.msg);
}
// 当后端返回码命中 `logoutCodes` 时,表示用户需要退出登录并跳转到登录页
const logoutCodes = import.meta.env.VITE_SERVICE_LOGOUT_CODES?.split(',') || [];
if (logoutCodes.includes(responseCode)) {
handleLogout();
return null;
}
// 当后端返回码命中 `modalLogoutCodes` 时,表示通过弹窗提示后再退出登录
const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
if (modalLogoutCodes.includes(responseCode) && !request.state.errMsgStack?.includes(response.data.msg)) {
request.state.errMsgStack = [...(request.state.errMsgStack || []), response.data.msg];
// 防止用户刷新页面绕过退出逻辑
window.addEventListener('beforeunload', handleLogout);
window.$messageBox
?.confirm(response.data.msg, $t('common.error'), {
confirmButtonText: $t('common.confirm'),
cancelButtonText: $t('common.cancel'),
type: 'error',
closeOnClickModal: false,
closeOnPressEscape: false
})
.then(() => {
logoutAndCleanup();
});
return null;
}
// 当后端返回码命中 `expiredTokenCodes` 时,表示 token 已过期,需要刷新 token
// `refreshToken` 接口不能再返回 `expiredTokenCodes` 中的错误码,否则会形成死循环,应返回 `logoutCodes` 或 `modalLogoutCodes`
const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || [];
if (expiredTokenCodes.includes(responseCode)) {
const success = await handleExpiredRequest(request.state);
if (success) {
const Authorization = getAuthorization();
Object.assign(response.config.headers, { Authorization });
return instance.request(response.config) as Promise<AxiosResponse>;
}
}
return null;
},
onError(error) {
// 请求失败时,在这里统一处理错误提示
let message = error.message;
let backendErrorCode = '';
// 获取后端错误信息和错误码
if (error.code === BACKEND_ERROR_CODE) {
message = error.response?.data?.msg || message;
backendErrorCode = String(error.response?.data?.code || '');
}
// 这类错误信息已经通过弹窗展示,不再重复提示
const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
if (modalLogoutCodes.includes(backendErrorCode)) {
return;
}
// token 过期时会自动刷新并重试请求,这里无需额外提示
const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || [];
if (expiredTokenCodes.includes(backendErrorCode)) {
return;
}
showErrorMsg(request.state, message);
}
}
)
);
export const demoRequest = createRequest(
{
baseURL: otherBaseURL.demo
},
{
transform(response: AxiosResponse<App.Service.DemoResponse>) {
return response.data.result;
},
async onRequest(config) {
const { headers } = config;
// 设置 token
const token = localStg.get('token');
const Authorization = token ? `Bearer ${token}` : null;
Object.assign(headers, { Authorization });
return config;
},
isBackendSuccess(response) {
// 当后端返回码为 "200" 时,表示请求成功
// 如有需要可以自行调整这段逻辑
return response.data.status === '200';
},
async onBackendFail(_response) {
// 当后端返回码不是 "200" 时,表示请求失败
// 例如token 过期后可以在这里刷新 token 并重试请求
},
onError(error) {
// 请求失败时,在这里统一处理错误提示
let message = error.message;
// 展示后端返回的错误信息
if (error.code === BACKEND_ERROR_CODE) {
message = error.response?.data?.message || message;
}
window.$message?.error(message);
}
}
);