/
tsps
/
lk
Обзор
Документация
Войти
/
tsps
/
lk
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
master
src/lib/api/client.ts
99 строк
3 KB
Василий Петров
Загрузка аудио с поллингом
01 апр 2026, 15:03
01 апр 2026, 15:03
c90f57a
Код
Авторство
О чём код?
import { API_BASE_URL } from './config'; import { useAuthStore } from '@/store/authStore'; interface ApiFetchOptions extends RequestInit { params?: Record<string, string | number | boolean>; responseType?: 'json' | 'text' | 'blob'; } /** * Универсальная функция для запросов к API личного кабинета * @param endpoint — путь после /api/lk (например, '/login') * @param options — стандартные параметры fetch + опционально params */ export async function apiFetch( endpoint: string, options?: ApiFetchOptions ) { // Обработка query-параметров let url = API_BASE_URL + endpoint; if (options?.params) { const searchParams = new URLSearchParams(); for (const [key, value] of Object.entries(options.params)) { searchParams.append(key, String(value)); } url += '?' + searchParams.toString(); } // Получаем токен из Zustand const accessToken = useAuthStore.getState().accessToken; const defaultHeaders: HeadersInit = {}; // Content-Type ставим только для JSON-запросов (не для FormData) // Браузер сам выставит multipart/form-data с boundary при отправке файла if (!(options?.body instanceof FormData)) { defaultHeaders['Content-Type'] = 'application/json'; } // Позволяем переопределить заголовки из options if (options?.headers) { Object.assign(defaultHeaders, options.headers); } // Если есть токен — добавляем в заголовок if (accessToken) { defaultHeaders['Authorization'] = `Bearer ${accessToken}`; } // Исключаем params и responseType из fetch-опций const { params, responseType, ...fetchOptions } = options || {}; const config: RequestInit = { ...fetchOptions, headers: defaultHeaders, }; const response = await fetch(url, config); if (!response.ok) { // Если статус 401 — сбросить сессию (logout) if (response.status === 401) { useAuthStore.getState().logout(); console.warn('Получен 401 — сессия недействительна. Выполняем logout.'); } // Пытаемся прочитать тело ошибки как JSON let errorMessage = `HTTP error! status: ${response.status}`; try { const errorData = await response.json(); errorMessage = errorData.detail || errorData.message || errorMessage; } catch { // Если не JSON — оставляем стандартное сообщение } throw new Error(errorMessage); } // Если ответ 204 (No Content) — возвращаем null if (response.status === 204) { return null; } // Обработка в зависимости от responseType if (responseType === 'blob') { return response.blob(); } if (responseType === 'text') { return response.text(); } // По умолчанию пытаемся парсить JSON const contentType = response.headers.get('content-type'); if (contentType && contentType.includes('application/json')) { return response.json(); } // Если не JSON — возвращаем текст return response.text(); }