/
gr.ev.vl
/
TestGen
Обзор
Документация
Войти
/
gr.ev.vl
/
TestGen
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
backend/frontend/src/api/client.ts
105 строк
3 KB
gr.ev.vl
Initial commit
06 июн 2026, 02:41
06 июн 2026, 02:41
02fb1fb
Код
Авторство
О чём код?
/** * HTTP-клиент на основе Axios. */ import axios, { AxiosError, InternalAxiosRequestConfig, AxiosResponse } from "axios"; import { getAccessToken, setTokens, clearTokens } from "../utils/tokens"; import { API_BASE_URL, API_TIMEOUT } from "../constants/config"; import type { ApiError, ApiErrorResponse } from "../types/api"; const apiClient = axios.create({ baseURL: API_BASE_URL, timeout: API_TIMEOUT, headers: { "Content-Type": "application/json", Accept: "application/json", }, }); let isRefreshing = false; let failedQueue: Array<{ resolve: (token: string) => void; reject: (error: unknown) => void; }> = []; function processQueue(error: unknown, token: string | null = null) { failedQueue.forEach(({ resolve, reject }) => { if (error) { reject(error); } else { resolve(token!); } }); failedQueue = []; } apiClient.interceptors.request.use( (config: InternalAxiosRequestConfig) => { const token = getAccessToken(); if (token && config.headers) { config.headers.Authorization = `Bearer ${token}`; } return config; }, (error) => Promise.reject(error), ); apiClient.interceptors.response.use( (response: AxiosResponse) => response, async (error: AxiosError<ApiErrorResponse>) => { const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean }; if (error.response?.status === 401 && !originalRequest._retry) { if (isRefreshing) { return new Promise<string>((resolve, reject) => { failedQueue.push({ resolve, reject }); }) .then((token) => { if (originalRequest.headers) { originalRequest.headers.Authorization = `Bearer ${token}`; } return apiClient(originalRequest); }) .catch((err) => Promise.reject(err)); } originalRequest._retry = true; isRefreshing = true; try { const refreshToken = localStorage.getItem("refresh_token"); if (!refreshToken) throw new Error("No refresh token"); const response = await axios.post(`${API_BASE_URL}/auth/refresh`, { refresh_token: refreshToken, }); const { access_token, refresh_token } = response.data; setTokens(access_token, refresh_token); processQueue(null, access_token); if (originalRequest.headers) { originalRequest.headers.Authorization = `Bearer ${access_token}`; } return apiClient(originalRequest); } catch (refreshError) { processQueue(refreshError, null); clearTokens(); window.location.href = "/login"; return Promise.reject(refreshError); } finally { isRefreshing = false; } } const apiError: ApiError = { status: error.response?.status, code: error.response?.data?.error?.code || "unknown_error", message: error.response?.data?.error?.message || error.message || "Произошла ошибка", details: error.response?.data?.error?.details || {}, }; return Promise.reject(apiError); }, ); export default apiClient;