import axios, { type AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios' import { jwtDecode, JwtPayload } from 'jwt-decode' import { PERMISSION_ACCESS_DENIED, PERMISSION_TOKEN_HAS_EXPIRED, PERMISSION_TOKEN_ILLEGAL, PERMISSION_TOKEN_RENEW_SUCCESS, PERMISSION_UNAUTHORIZED, SYSTEM_REQUEST_TOO_FREQUENT } from '@/constants/common.constants' import { getRedirectUrl } from '@/util/route' import { getToken, setToken, removeToken } from '@/util/auth' const service: AxiosInstance = axios.create({ baseURL: import.meta.env.VITE_API_URL, timeout: 30000, withCredentials: false }) service.defaults.paramsSerializer = (params: Record) => { return Object.keys(params) .filter((it) => { return Object.prototype.hasOwnProperty.call(params, it) }) .reduce((pre, curr) => { return params[curr] !== null && params[curr] !== undefined ? (pre !== '' ? pre + '&' : '') + curr + '=' + encodeURIComponent(params[curr]) : pre }, '') } service.interceptors.request.use( async (config) => { let token = getToken() if (token !== null) { const jwt = jwtDecode(token) if (!jwt.exp) { return config } if ( jwt.exp * 1000 - new Date().getTime() < 1200000 && jwt.exp * 1000 - new Date().getTime() > 0 ) { await axios .get(import.meta.env.VITE_API_TOKEN_URL, { headers: { Authorization: `Bearer ${token}` } }) .then((value: AxiosResponse<_Response>) => { const response = value.data if (response.code === PERMISSION_TOKEN_RENEW_SUCCESS) { setToken(response.data?.token ?? '') } }) } token = getToken() config.headers.set('Authorization', `Bearer ${token}`) } return config }, async (error) => { return await Promise.reject(error) } ) service.interceptors.response.use( (response: AxiosResponse<_Response>) => { switch (response.data.code) { case PERMISSION_UNAUTHORIZED: removeToken() void message.error({ content: ( <> 未登录 ), key: 'NO_LOGIN' }) setTimeout(() => { location.reload() }, 1500) throw response?.data case PERMISSION_TOKEN_ILLEGAL: case PERMISSION_TOKEN_HAS_EXPIRED: removeToken() void message.error({ content: ( <> 登录已过期 ), key: 'LOGIN_HAS_EXPIRED' }) setTimeout(() => { location.replace( getRedirectUrl('/login', `${location.pathname}${location.search}`) ) }, 1500) throw response?.data case PERMISSION_ACCESS_DENIED: void message.error({ content: ( <> 暂无权限操作 ), key: 'ACCESS_DENIED' }) throw response?.data case SYSTEM_REQUEST_TOO_FREQUENT: void message.warning({ content: ( <> 请求过于频繁,请稍后重试 ), key: 'REQUEST_TOO_FREQUENT' }) throw response?.data } return response }, async (error: AxiosError) => { if ( error.code === 'ETIMEDOUT' || (error.code === 'ECONNABORTED' && error.message.includes('timeout')) ) { void message.error({ content: '请求超时,请稍后重试', key: 'TIMEOUT' }) } else { void message.error({ content: ( <> 服务器出错,请稍后重试 ), key: 'SERVER_ERROR' }) } return await Promise.reject(error?.response?.data) } ) const request = { async get(url: string, data?: object): Promise>> { return await request.request('GET', url, { params: data }) }, async post(url: string, data?: object): Promise>> { return await request.request('POST', url, { data }) }, async put(url: string, data?: object): Promise>> { return await request.request('PUT', url, { data }) }, async patch(url: string, data?: object): Promise>> { return await request.request('PATCH', url, { data }) }, async delete(url: string, data?: object): Promise>> { return await request.request('DELETE', url, { data }) }, async request( method = 'GET', url: string, data?: AxiosRequestConfig ): Promise>> { return await new Promise((resolve, reject) => { service({ method, url, ...data }) .then((res) => { resolve(res as unknown as Promise>>) }) .catch((e: Error | AxiosError) => { reject(e) }) }) } } export default request