|  |  |  | 
|---|
|  |  |  | import qs from 'qs'; | 
|---|
|  |  |  | import NProgress from '../progress'; | 
|---|
|  |  |  | import { loadEnv } from '@build/index'; | 
|---|
|  |  |  | import { getToken, getUserInfo } from '../storage'; | 
|---|
|  |  |  | import { useUserStoreHook } from '@/store/modules/user'; | 
|---|
|  |  |  | import { ElLoading as Loading, ElNotification } from 'element-plus'; | 
|---|
|  |  |  | import { router } from '@/router'; | 
|---|
|  |  |  | import { Message, tokenIsExpired } from '@/utils'; | 
|---|
|  |  |  | import { httpLoggerRecord } from '../LoggerRecord'; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 加载环境变量 VITE_PROXY_DOMAIN(开发环境)  VITE_PROXY_DOMAIN_REAL(打包后的线上环境) | 
|---|
|  |  |  | const { VITE_PROXY_DOMAIN, VITE_PROXY_DOMAIN_REAL, DEV } = loadEnv(); | 
|---|
|  |  |  | 
|---|
|  |  |  | const RefreshTokenUrl = '/GetTokenByRefreshToken'; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** 请求白名单,放置一些不需要token的接口(通过设置请求白名单,防止token过期后再请求造成的死循环问题) */ | 
|---|
|  |  |  | const whiteList = [RefreshTokenUrl, '/GetToken']; | 
|---|
|  |  |  | const whiteList = [RefreshTokenUrl, '/passwordLogin']; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | let loadingInstance: ReturnType<typeof Loading.service>; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  | success: boolean; | 
|---|
|  |  |  | data: any; | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * http状态吗 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | code?: number; | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 错误码 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | error?: number; | 
|---|
|  |  |  | errorCode?: string; | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 错误信息 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | msg?: string; | 
|---|
|  |  |  | showType?: ErrorShowType; | 
|---|
|  |  |  | traceId?: string; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | interface ErrorResponse { | 
|---|
|  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | interface ErrorInfo { | 
|---|
|  |  |  | errorCode?: number; | 
|---|
|  |  |  | errorCode?: string; | 
|---|
|  |  |  | errorMessage?: string; | 
|---|
|  |  |  | showType?: ErrorShowType; | 
|---|
|  |  |  | data: any; | 
|---|
|  |  |  | 
|---|
|  |  |  | // 错误接收及处理 | 
|---|
|  |  |  | errorHandler: (error, opts) => { | 
|---|
|  |  |  | console.log('error: ', error); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | const url = opts.url ?? ''; | 
|---|
|  |  |  | httpLoggerRecord.error({ | 
|---|
|  |  |  | message: `[${url}] 请求错误`, | 
|---|
|  |  |  | httpParams: { | 
|---|
|  |  |  | url: url, | 
|---|
|  |  |  | //@ts-ignore | 
|---|
|  |  |  | traceId: error?.info?.traceId, | 
|---|
|  |  |  | stackTrace: error.stack, | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | args: [{ data: opts.data, params: opts.params, headers: opts.headers }], | 
|---|
|  |  |  | }); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (opts?.skipErrorHandler) throw error; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (opts?.customErrorHandler) { | 
|---|
|  |  |  | 
|---|
|  |  |  | const errorInfo: ErrorInfo | undefined = (error as any).info; | 
|---|
|  |  |  | if (errorInfo) { | 
|---|
|  |  |  | const { errorMessage, errorCode } = errorInfo; | 
|---|
|  |  |  | if (Number(errorCode) === 401) { | 
|---|
|  |  |  | handleLogout(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | switch (errorInfo.showType) { | 
|---|
|  |  |  | case ErrorShowType.SILENT: | 
|---|
|  |  |  | // do nothing | 
|---|
|  |  |  | 
|---|
|  |  |  | } else if ((error as AxiosError<ResponseStructure, IRequestOptions>).response) { | 
|---|
|  |  |  | // Axios 的错误 | 
|---|
|  |  |  | // 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围 | 
|---|
|  |  |  | handleAxiosResponseError(error as AxiosError<ErrorResponse, IRequestOptions>); | 
|---|
|  |  |  | handleAxiosResponseError(error as AxiosError<ResponseStructure, IRequestOptions>); | 
|---|
|  |  |  | // Message.errorMessage(`Response status:${(error as AxiosError).response.status}`); | 
|---|
|  |  |  | } else if ((error as AxiosError).request) { | 
|---|
|  |  |  | // 请求已经成功发起,但没有收到响应 | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 错误抛出 | 
|---|
|  |  |  | errorThrower: (res) => { | 
|---|
|  |  |  | const { success, data, error: errorCode, msg, showType } = res; | 
|---|
|  |  |  | const { success, data, errorCode, msg, showType } = res; | 
|---|
|  |  |  | if (!success) { | 
|---|
|  |  |  | const error: any = new Error(msg); | 
|---|
|  |  |  | error.name = 'BizError'; | 
|---|
|  |  |  | 
|---|
|  |  |  | NProgress.start(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | const token = getToken(); | 
|---|
|  |  |  | httpLoggerRecord.info({ | 
|---|
|  |  |  | message: `[${$config.url}] 请求开始`, | 
|---|
|  |  |  | httpParams: { | 
|---|
|  |  |  | url: $config.url, | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | args: [{ data: $config.data, params: $config.params, headers: $config.headers }], | 
|---|
|  |  |  | }); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | const userInfo = getUserInfo(); | 
|---|
|  |  |  | const userStore = useUserStoreHook(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | const userInfo = userStore.userInfo; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | const { showLoading = true, mock } = $config; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | return new Promise((resolve) => { | 
|---|
|  |  |  | if (token && $config.withCredentials) { | 
|---|
|  |  |  | if (tokenIsExpired(userInfo)) { | 
|---|
|  |  |  | if (!BoleRequest.refreshTokenPending) { | 
|---|
|  |  |  | const userStore = useUserStoreHook(); | 
|---|
|  |  |  | BoleRequest.refreshTokenPending = true; | 
|---|
|  |  |  | // token过期刷新 | 
|---|
|  |  |  | userStore | 
|---|
|  |  |  | .refreshToken({ | 
|---|
|  |  |  | refreshToken: userInfo.refreshToken, | 
|---|
|  |  |  | clientId: userStore.accountInfo.client_id, | 
|---|
|  |  |  | }) | 
|---|
|  |  |  | .then((res) => { | 
|---|
|  |  |  | $config.headers['Authorization'] = 'Bearer ' + res.accessToken; | 
|---|
|  |  |  | BoleRequest.requests.forEach((cb) => cb(res.accessToken)); | 
|---|
|  |  |  | BoleRequest.requests = []; | 
|---|
|  |  |  | }) | 
|---|
|  |  |  | .finally(() => { | 
|---|
|  |  |  | BoleRequest.refreshTokenPending = false; | 
|---|
|  |  |  | }); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | resolve(BoleRequest.retryOriginalRequest($config)); | 
|---|
|  |  |  | } else { | 
|---|
|  |  |  | $config.headers['Authorization'] = 'Bearer ' + token; | 
|---|
|  |  |  | resolve($config); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (userInfo.accessToken && $config.withCredentials) { | 
|---|
|  |  |  | $config.headers['Authorization'] = 'Bearer ' + userInfo.accessToken; | 
|---|
|  |  |  | $config.headers['X-Authorization'] = 'Bearer ' + userInfo.refreshToken; | 
|---|
|  |  |  | resolve($config); | 
|---|
|  |  |  | } else { | 
|---|
|  |  |  | resolve($config); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | 
|---|
|  |  |  | (response) => { | 
|---|
|  |  |  | const $config = response.config as IRequestOptions; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | httpLoggerRecord.info({ | 
|---|
|  |  |  | message: `[${$config.url}] 请求结束`, | 
|---|
|  |  |  | httpParams: { | 
|---|
|  |  |  | url: $config.url, | 
|---|
|  |  |  | traceId: response.data?.traceId, | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | args: [{ data: $config.data, params: $config.params, headers: $config.headers }], | 
|---|
|  |  |  | }); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | const { needNProcess, getResponse = false } = $config; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 关闭进度条动画 | 
|---|
|  |  |  | 
|---|
|  |  |  | NProgress.done(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | const userStore = useUserStoreHook(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (response.headers['x-access-token']) { | 
|---|
|  |  |  | userStore.setToken(response.headers['access-token']); | 
|---|
|  |  |  | userStore.setUserInfo({ | 
|---|
|  |  |  | accessToken: response.headers['access-token'], | 
|---|
|  |  |  | refreshToken: response.headers['x-access-token'], | 
|---|
|  |  |  | }); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | endLoading(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | return getResponse ? response : (response.data as any).result; | 
|---|
|  |  |  | return getResponse ? response : response.data.data; | 
|---|
|  |  |  | }, | 
|---|
|  |  |  | (error) => { | 
|---|
|  |  |  | endLoading(); | 
|---|
|  |  |  | 
|---|
|  |  |  | [505]: 'HTTP版本不受支持', | 
|---|
|  |  |  | }; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | function handleAxiosResponseError(error: AxiosError<ErrorResponse, IRequestOptions>) { | 
|---|
|  |  |  | function handleAxiosResponseError(error: AxiosError<ResponseStructure, IRequestOptions>) { | 
|---|
|  |  |  | if (error.response.config.url.toLowerCase().includes(RefreshTokenUrl.toLowerCase())) { | 
|---|
|  |  |  | handleLogout(); | 
|---|
|  |  |  | return; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (error && error.response) { | 
|---|
|  |  |  | let message = ErrorMessageMap[error.response?.status] ?? '请求错误'; | 
|---|
|  |  |  | if (error.response.data?.error?.message) { | 
|---|
|  |  |  | message = error.response.data?.error?.message; | 
|---|
|  |  |  | if (error.response.data?.msg) { | 
|---|
|  |  |  | message = error.response.data?.msg; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (error.response?.status === 401) { | 
|---|
|  |  |  | if (error.response?.status === 401 || error.response.data.code === 401) { | 
|---|
|  |  |  | handleLogout(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | Message.errorMessage(message); | 
|---|