Files
Situation-Awareness-Platfor…/src/utils/request.ts
2025-03-17 19:25:02 +08:00

195 lines
6.5 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 axios, { type AxiosRequestConfig } from 'axios';
import { dealWarning } from './status';
import router from '@/router';
import { repoInfoStore } from '@/stores/Repo';
import { useGlobalInfoStore } from '@/stores/Global';
import { cutParamsInUrl, getSignUtmSource } from './index';
import { Message } from 'vue-devui/message';
import degradeInterceptor from './degradeInterceptor';
const handleError = dealWarning();
/** 设置用户中心相关api迁移时的api前缀 */
const setPassportPrefix = (url: string, method: string) => {
const prefix = (import.meta as any).env.VITE_PASSPORT_PREFIX;
if (prefix) {
if (url?.includes('/api/v1/user/')) {
// 用户信息相关
return `${url}`;
}
if (url?.includes('/api/v1/oauth/')) {
// 用户权限
return `${prefix}${url}`;
}
if (url?.includes('/api/v1/internal/messages')) {
// 消息通知
return `${prefix}${url}`;
}
if (url?.includes('/api/v1/follow')) {
// 关注状态
return `${prefix}${url}`;
}
if (url?.includes('/api/v1/obs') && method === 'get') {
// 图片相关
return `${prefix}${url}`;
}
}
return url;
};
export const baseURL = (import.meta as any).env.VITE_API_HOST;
export const baseDevURL = (import.meta as any).env.VITE_DEV_API_HOST;
type CustomConfigs = {
// 是否使用自定义的错误处理
customError?: boolean;
};
interface PendingTask {
config: AxiosRequestConfig;
resolve: Function;
}
let refreshing = false;
const queue: PendingTask[] = [];
const refreshToken = async () => axios.request({
url: baseURL + `${(import.meta as any).env.VITE_PASSPORT_PREFIX || ''}` + '/api/v1/user/token/refresh',
method: 'post',
data: {
refresh_token: localStorage.getItem('refresh_token')
},
headers: {
Authorization: 'Bearer ' + localStorage.getItem('access_token'),
'content-type': 'application/x-www-form-urlencoded'
},
withCredentials: true
});
const proxyService = (params: any, customConfigs?: CustomConfigs) => {
const service = axios.create({
baseURL: params.apiType === 'devApi' ? baseDevURL : baseURL,
timeout: 15000,
withCredentials: true
});
/** user api相关请求白名单 */
const whiteList = ['/login', 'login/mobile', '/sendVeriCode', '/register', '/quickLogin', '/quickRegister', '/forgetCode', '/forgetPassword', '/checkSameUser', '/token'];
const notAuthorization = (url: string = '') => {
return whiteList.some((str) => url.includes(str));
};
// request 拦截器
service.interceptors.request.use(
(config) => {
// 配置请求头
const globalStore = useGlobalInfoStore();
const repoStore = repoInfoStore();
const currentRoute = router?.currentRoute?.value;
const repoId = currentRoute?.meta?.type === 'repo' ? repoStore.repoInfo?.id : undefined;
const title = config.headers['homeweb-page-title'] || currentRoute?.meta?.reportTitle;
delete config.headers['homeweb-page-title'];
if (title && params.apiType !== 'devApi') {
// devpress接口不需要上报
config.headers['page-title'] = encodeURIComponent(title);
}
if (currentRoute.name === 'homepage' && params.apiType !== 'devApi') {
const homeTitleConfig = {
0: '个人主页',
1: '组织主页'
};
const pageTitle = homeTitleConfig[globalStore.namespaceType as 0 | 1];
config.headers['page-title'] = encodeURIComponent(pageTitle);
}
if (repoId && params.apiType !== 'devApi') {
config.headers['page-repo-id'] = repoId;
}
if (params.apiType !== 'devApi') {
config.headers['page-ref'] = encodeURIComponent(cutParamsInUrl(window.page_ref || ''));
config.headers['page-uri'] = encodeURIComponent(cutParamsInUrl(window.location.href || ''));
config.headers['gitcode-utm-source'] = encodeURIComponent(getSignUtmSource());
}
const access_token = window.localStorage.getItem('access_token');
const { url } = config;
if (access_token && !notAuthorization(url)) {
config.headers.Authorization = `Bearer ${access_token}`;
}
/** 修改用户模块前缀名称 */
config.url = setPassportPrefix(config.url as string, config.method as string);
return config;
},
(error) => {
return Promise.reject(error);
}
);
service.interceptors.request.use(degradeInterceptor.onRequestFulfilled, degradeInterceptor.onRequestRejected);
// response 拦截器
service.interceptors.response.use(
(response) => {
return response;
},
async (error) => {
const { response } = error;
const { config } = response || {};
if (refreshing) {
return new Promise((resolve) => {
queue.unshift({
config,
resolve
});
});
}
if (response?.status === 401 && localStorage.getItem('access_token') && !config?.url.includes('/token/refresh')) {
refreshing = true;
try {
const res = await refreshToken();
refreshing = false;
if (res.status === 200) {
const { access_token, refresh_token } = res.data;
localStorage.setItem('access_token', access_token);
localStorage.setItem('refresh_token', refresh_token);
queue.forEach(({ config, resolve }) => {
if (config.headers) {
config.headers.Authorization = `Bearer ${access_token}`;
}
resolve(axios(config));
});
queue.splice(0);
config.headers.Authorization = `Bearer ${access_token}`;
return axios(config);
} else {
handleError({}, true);
return Promise.reject(res.data);
}
} catch (e) {
handleError({}, true);
}
} else if (response) {
// 请求已发出但是不在2xx的范围
// showMessage(response);
response.data.http_status = response.status;
if (!customConfigs || !customConfigs.customError) {
handleError(response);
}
return Promise.reject(response.data);
} else {
// 网络连接超时
const timeoutRegx = /\btimeout\b/;
if (error?.message && timeoutRegx.test(error.message)) {
Message.error('网络连接超时');
}
return Promise.reject(error);
}
}
);
service.interceptors.response.use(degradeInterceptor.onResponseFulfilled, degradeInterceptor.onResponseRejected);
return service(params);
};
export default proxyService;