151 lines
5.0 KiB
JavaScript
151 lines
5.0 KiB
JavaScript
import axios from 'axios'
|
||
import {useGlobalStatusStore} from '@/stores/useGlobalStatusStore';
|
||
import lang from '../i18n/i18n';
|
||
import {router} from "@/router";
|
||
import {createLoginRedirectHandler} from "@/utils/navigation.mjs";
|
||
import { decodeBlobAPIError } from './apiResponse.mjs'
|
||
|
||
//创建axios的一个实例
|
||
const http = axios.create({
|
||
baseURL: import.meta.env.VITE_APP_URL, //接口统一域名
|
||
timeout: 60000,
|
||
// 初始化授权和登录会话都依赖服务端 Cookie;开发代理或反向代理跨源时也必须携带 Cookie。
|
||
withCredentials: true,
|
||
xsrfCookieName: 'smail_csrf',
|
||
xsrfHeaderName: 'X-CSRF-Token',
|
||
withXSRFToken: true, //设置超时
|
||
headers: {
|
||
'Lang': lang.lang
|
||
}
|
||
});
|
||
|
||
let redirectToLogin = null;
|
||
|
||
function handleLoginRedirect() {
|
||
const currentRoute = router.currentRoute.value;
|
||
if (currentRoute?.name === 'login' || currentRoute?.name === 'login-verification') {
|
||
return Promise.resolve(false);
|
||
}
|
||
useGlobalStatusStore().clear();
|
||
if (!redirectToLogin) {
|
||
redirectToLogin = createLoginRedirectHandler(router);
|
||
}
|
||
return redirectToLogin();
|
||
}
|
||
|
||
//响应拦截器
|
||
function attachApiErrorDetails(error) {
|
||
const payload = error?.response?.data
|
||
const details = payload?.data
|
||
|
||
if (payload && typeof payload === 'object') {
|
||
error.apiErrorCode = typeof details?.code === 'string' ? details.code : ''
|
||
error.apiRequestId = typeof details?.requestId === 'string' ? details.requestId : ''
|
||
error.apiErrorFields = details?.fields && typeof details.fields === 'object' ? details.fields : {}
|
||
if (typeof payload.errorMsg === 'string' && payload.errorMsg.trim()) {
|
||
error.message = payload.errorMsg
|
||
}
|
||
}
|
||
|
||
return error
|
||
}
|
||
|
||
function getRequestPath(config) {
|
||
const rawUrl = String(config?.url || '').split('?')[0]
|
||
try {
|
||
const origin = typeof window !== 'undefined' ? window.location.origin : 'http://localhost'
|
||
return new URL(rawUrl, config?.baseURL || origin).pathname
|
||
} catch (error) {
|
||
return rawUrl
|
||
}
|
||
}
|
||
|
||
function isSetupRequest(config) {
|
||
const path = getRequestPath(config)
|
||
return path === '/api/setup' || path === '/api/v1/setup' || path === '/__smail_setup_bootstrap'
|
||
}
|
||
|
||
function isAuthenticationRefreshRequest(config) {
|
||
const path = getRequestPath(config)
|
||
return path === '/api/user/info' || path === '/api/v1/user/info'
|
||
}
|
||
|
||
function isAuthenticationFailureError(error) {
|
||
const errorCode = error?.response?.data?.data?.code
|
||
if (errorCode === 'RECENT_AUTH_REQUIRED') return false
|
||
return error?.response?.data?.errorNo === 403
|
||
|| (error?.response?.status === 403 && isAuthenticationRefreshRequest(error.config))
|
||
}
|
||
|
||
http.interceptors.response.use(async (response) => {
|
||
//响应成功
|
||
await decodeBlobAPIError(response)
|
||
if (response.data?.errorNo === 403
|
||
&& response.data?.data?.code !== 'RECENT_AUTH_REQUIRED'
|
||
&& !isSetupRequest(response.config)
|
||
&& !isAuthenticationRefreshRequest(response.config)) {
|
||
await handleLoginRedirect();
|
||
}
|
||
return response.data;
|
||
}, async (error) => {
|
||
//响应错误
|
||
await decodeBlobAPIError(error.response)
|
||
if (error.response && error.response.status) {
|
||
let message = ""
|
||
switch (error.response.status) {
|
||
case 400:
|
||
message = '请求错误';
|
||
break;
|
||
case 401:
|
||
message = '请求错误';
|
||
break;
|
||
case 403:
|
||
if (isSetupRequest(error.config)) {
|
||
message = lang.setup_failed
|
||
} else if (isAuthenticationRefreshRequest(error.config)) {
|
||
message = '登录状态已失效'
|
||
} else if (isAuthenticationFailureError(error)) {
|
||
await handleLoginRedirect();
|
||
} else {
|
||
message = '无权访问'
|
||
}
|
||
break;
|
||
case 404:
|
||
message = '请求地址出错';
|
||
break;
|
||
case 408:
|
||
message = '请求超时';
|
||
break;
|
||
case 500:
|
||
message = '服务器内部错误!';
|
||
break;
|
||
case 501:
|
||
message = '服务未实现!';
|
||
break;
|
||
case 502:
|
||
message = '网关错误!';
|
||
break;
|
||
case 503:
|
||
message = '服务不可用!';
|
||
break;
|
||
case 504:
|
||
message = '网关超时!';
|
||
break;
|
||
case 505:
|
||
message = 'HTTP版本不受支持';
|
||
break;
|
||
default:
|
||
// eslint-disable-next-line no-unused-vars
|
||
message = '请求失败';
|
||
}
|
||
const enrichedError = attachApiErrorDetails(error)
|
||
if (message && !enrichedError.response?.data?.errorMsg) {
|
||
enrichedError.message = message
|
||
}
|
||
return Promise.reject(enrichedError)
|
||
}
|
||
return Promise.reject(attachApiErrorDetails(error));
|
||
});
|
||
|
||
export {http};
|