Axios: инстансы и интерсепторы

↑ 5.4 Работа с API: REST, GraphQL, WebSocket · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Типовая задача: подстановка токена, обновление при 401, общий обработчик ошибок.

Объяснение

export const api = axios.create({ baseURL: import.meta.env.VITE_API_URL, timeout: 15_000, headers: { Accept: "application/json" }, withCredentials: false });
 
api.interceptors.request.use((cfg) => {
  const token = useAuthStore().accessToken;
  if (token) cfg.headers.Authorization = `Bearer ${token}`;
  cfg.headers["X-Request-Id"] = crypto.randomUUID();                 // корреляция с логами бэкенда
  return cfg;
});
 
// Обновление токена при 401 с очередью запросов и защитой от гонок
let refreshing: Promise<string> | null = null;
api.interceptors.response.use(
  (res) => res,
  async (error: AxiosError) => {
    const original = error.config as AxiosRequestConfig & { _retry?: boolean };
    if (error.response?.status === 401 && !original._retry && !original.url?.includes("/auth/")) {
      original._retry = true;
      refreshing ??= useAuthStore().refresh().finally(() => (refreshing = null));      // один refresh на все запросы
      try { const t = await refreshing; original.headers = { ...original.headers, Authorization: `Bearer ${t}` }; return api(original); }
      catch { useAuthStore().logout(); }
    }
    return Promise.reject(normalizeError(error));                      // единый формат ошибок
  },
);

Что типично делают интерсепторы:

ЗадачаИнтерсептор
Токен, язык (Accept-Language), tenantrequest
Корреляционный id, трассировка (traceparent)request
Обновление токена, редирект на логинresponse (401)
Нормализация ошибок, показ уведомленийresponse
Логирование, метрикиоба
Повторыresponse (с ограничением)
Лоадерсчётчик активных запросов

Несколько инстансов: публичный API, внутренний, внешние сервисы — с разными baseURL/авторизацией. Типизация: api.get<Order[]>("/orders"), обобщения обёртки.

Перевод на fetch-адаптер или ky/ofetch возможен; логика интерсепторов сохраняется (обёртка с хуками).

Нюансы и подводные камни

  • Бесконечный цикл при повторе запроса с 401: флаг _retry, исключение auth-эндпоинтов.
  • Параллельные 401 вызывают несколько refresh: объединяйте в один промис.
  • Интерсептор не должен показывать уведомление на каждую ошибку (ожидаемые 4xx обрабатываются локально).
  • Утечки при добавлении интерсепторов в setup без eject.
  • Секреты в логах интерсептора.

Практика

  1. Реализуйте обновление токена с очередью запросов.
  2. Настройте единый формат ошибок и связь с Vue Query.
  3. Добавьте X-Request-Id/traceparent в исходящие запросы.

Вопросы с ответами

Связанные темы