first commit
This commit is contained in:
125
src/boot/axios.ts
Normal file
125
src/boot/axios.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import { boot } from 'quasar/wrappers';
|
||||
import type { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||
import axios from 'axios';
|
||||
import { useLogin } from 'src/vueLib/login/useLogin';
|
||||
|
||||
const host = window.location.hostname;
|
||||
export const portApp = 9500;
|
||||
|
||||
// Create axios instance
|
||||
export const appApi: AxiosInstance = axios.create({
|
||||
baseURL: `http://${host}:${portApp}/api`,
|
||||
timeout: 10000,
|
||||
withCredentials: true,
|
||||
});
|
||||
|
||||
interface RetryRequestConfig extends AxiosRequestConfig {
|
||||
_retry?: boolean;
|
||||
}
|
||||
|
||||
const noRefreshEndpoints = ['/login', '/secure/login/refresh', '/logout'];
|
||||
|
||||
// ========= Refresh Queue Handling ========= //
|
||||
let isRefreshing = false;
|
||||
|
||||
interface FailedRequest {
|
||||
resolve: (value?: unknown) => void;
|
||||
reject: (reason?: Error) => void;
|
||||
}
|
||||
|
||||
let failedQueue: FailedRequest[] = [];
|
||||
|
||||
const processQueue = (error: Error | null): void => {
|
||||
failedQueue.forEach((prom) => {
|
||||
if (error) prom.reject(error);
|
||||
else prom.resolve();
|
||||
});
|
||||
failedQueue = [];
|
||||
};
|
||||
// ========================================= //
|
||||
|
||||
appApi.interceptors.response.use(
|
||||
(response: AxiosResponse) => response,
|
||||
|
||||
async (error: AxiosError<unknown, RetryRequestConfig>): Promise<AxiosResponse> => {
|
||||
const { refresh, logout } = useLogin();
|
||||
const originalRequest = error.config as RetryRequestConfig | undefined;
|
||||
|
||||
// Skip refresh for login/logout endpoints
|
||||
if (
|
||||
!originalRequest ||
|
||||
noRefreshEndpoints.some((url) => originalRequest.url?.includes(url ?? ''))
|
||||
) {
|
||||
const message = error instanceof Error ? error.message : JSON.stringify(error);
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
// Handle unauthorized responses
|
||||
if (error.response?.status === 401 && !originalRequest._retry) {
|
||||
if (isRefreshing) {
|
||||
// Wait until refresh completes
|
||||
return new Promise<AxiosResponse>((resolve, reject) => {
|
||||
failedQueue.push({
|
||||
resolve: () => {
|
||||
void appApi(originalRequest).then(resolve).catch(reject);
|
||||
},
|
||||
reject,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
originalRequest._retry = true;
|
||||
isRefreshing = true;
|
||||
|
||||
try {
|
||||
const refreshed = await refresh().catch(() => false);
|
||||
processQueue(null);
|
||||
|
||||
if (refreshed) {
|
||||
// Token refreshed successfully → retry request
|
||||
return appApi(originalRequest);
|
||||
}
|
||||
|
||||
// Refresh returned false → logout
|
||||
console.warn('[Axios] Refresh returned false, logging out');
|
||||
await logout();
|
||||
throw new Error('Token refresh failed');
|
||||
} catch (err) {
|
||||
const e = err instanceof Error ? err : new Error(String(err));
|
||||
console.error('[Axios] Token refresh failed:', e.message);
|
||||
|
||||
// Always logout, even if refresh throws
|
||||
try {
|
||||
await logout();
|
||||
} catch (logoutErr) {
|
||||
console.error('[Axios] Logout failed after token refresh error:', logoutErr);
|
||||
}
|
||||
|
||||
processQueue(e);
|
||||
throw e;
|
||||
} finally {
|
||||
isRefreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Not a 401 — rethrow as Error
|
||||
|
||||
let msg = '';
|
||||
if (error && (error as AxiosError).isAxiosError) {
|
||||
const axiosError = error as AxiosError<{ message?: string }>;
|
||||
msg = axiosError.response?.data?.message ?? axiosError.message;
|
||||
} else {
|
||||
msg = error instanceof Error ? error.message : JSON.stringify(error);
|
||||
}
|
||||
|
||||
throw new Error(msg);
|
||||
},
|
||||
);
|
||||
|
||||
// ======== Boot registration for Quasar ======== //
|
||||
export default boot(({ app }) => {
|
||||
app.config.globalProperties.$axios = axios;
|
||||
app.config.globalProperties.$appApi = appApi;
|
||||
});
|
||||
|
||||
export { axios };
|
||||
Reference in New Issue
Block a user