Хотите заказать веб-сайт? Связаться с нами

Axios — профессиональные HTTP-запросы в React

Цель урока: научиться использовать Axios для работы с HTTP-запросами вместо нативного fetch. Понять, как настраивать интерсепторы, обрабатывать ошибки, создавать экземпляры клиента и упрощать работу с API в React-приложениях.

Axios — профессиональные HTTP-запросы в React

Введение: fetch vs Axios

В предыдущих уроках мы использовали нативный fetch для запросов к серверу. Он работает, но имеет ограничения.

Проблемы fetch

  1. Нет автоматической трансформации JSON — нужно дважды вызывать .json()
  2. Не бросает ошибки при статусах 4xx/5xx — нужно проверять response.ok вручную
  3. Нет интерсепторов — сложно добавлять заголовки или логировать запросы
  4. Нет отмены запросов — требует дополнительного кода
  5. Громоздкий синтаксис — много шаблонного кода

Главная мысль: Axios — это HTTP-клиент, который решает все проблемы fetch. Он даёт удобный API, автоматическую трансформацию JSON, интерсепторы, отмену запросов и единую обработку ошибок.

Сравнение fetch и Axios

Характеристика fetch Axios
Браузерная поддержка Встроен Требуется установка
JSON по умолчанию ❌ Нет (нужен .json()) ✅ Автоматически
Ошибки 4xx/5xx Не бросает ошибки ✅ Бросает ошибки
Интерсепторы ❌ Нет ✅ Есть
Отмена запросов Через AbortController ✅ Встроенная
Перехват ответов ❌ Нет ✅ Есть
Размер 0 байт (встроен) ~4kb

Установка и первый запрос

Установка:

npm install axios

Первый GET-запрос:

import axios from 'axios';

function Posts() {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    axios.get('https://api.example.com/posts')
      .then(response => {
        setPosts(response.data);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, []);

  if (loading) return <p>Загрузка...</p>;
  if (error) return <p>Ошибка: {error}</p>;

  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

Что происходит:

  1. axios.get() — выполняет GET-запрос
  2. response.data — уже готовый объект JSON (не нужно вызывать .json()!)
  3. catch — ловит любые ошибки (включая 404, 500 и сетевые)

Все HTTP-методы в Axios

import axios from 'axios';

// GET — получение данных
const getData = async () => {
  const response = await axios.get('/api/users');
  return response.data;
};

// POST — создание данных
const createPost = async (post) => {
  const response = await axios.post('/api/posts', post);
  return response.data;
};

// PUT — полное обновление
const updatePost = async (id, post) => {
  const response = await axios.put(`/api/posts/${id}`, post);
  return response.data;
};

// PATCH — частичное обновление
const patchPost = async (id, updates) => {
  const response = await axios.patch(`/api/posts/${id}`, updates);
  return response.data;
};

// DELETE — удаление
const deletePost = async (id) => {
  await axios.delete(`/api/posts/${id}`);
};

GET с параметрами:

// Способ 1 — через params (рекомендуется)
const response = await axios.get('/api/users', {
  params: {
    page: 2,
    limit: 10,
    sort: 'asc'
  }
});

// Способ 2 — через URL
const response = await axios.get('/api/users?page=2&limit=10');

POST с заголовками:

const response = await axios.post('/api/posts', 
  { title: 'Новый пост' },
  {
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer token123'
    }
  }
);

Создание экземпляра Axios (baseURL)

Вместо повторения базового URL в каждом запросе создают экземпляр:

// api.js
import axios from 'axios';

const api = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 5000, // таймаут 5 секунд
  headers: {
    'Content-Type': 'application/json'
  }
});

export default api;

Использование:

import api from './api';

// Все запросы теперь используют baseURL
const response = await api.get('/posts'); // → https://api.example.com/posts
const response = await api.post('/users', { name: 'Алексей' }); // → https://api.example.com/users
Из ноутбука появляются летающие светящиеся экраны

Оживи свой сайт. Освой JavaScript!

Статичная верстка — это только скелет. Наш онлайн-курс "JavaScript с нуля до профи" даст твоим страницам мышцы и нервы. Научись создавать слайдеры, формы, интерактивные карты и получать данные с сервера.

От теории — к реальным скриптам в твоём портфолио.

Подробнее о курсе

Интерсепторы — перехват запросов и ответов

Интерсепторы запросов — выполняются перед отправкой запроса:

// Добавляем токен авторизации ко всем запросам
api.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

Интерсепторы ответов — выполняются после получения ответа:

// Обрабатываем ошибки глобально
api.interceptors.response.use(
  (response) => {
    // Любой ответ с 2xx
    return response;
  },
  (error) => {
    // Любой ответ с 4xx/5xx
    if (error.response?.status === 401) {
      // Не авторизован — редирект на страницу входа
      window.location.href = '/login';
    }
    
    if (error.response?.status === 500) {
      console.error('Ошибка сервера:', error.response.data);
    }
    
    return Promise.reject(error);
  }
);

Полный пример:

// api.js
import axios from 'axios';

const api = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000,
});

// Request interceptor
api.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// Response interceptor
api.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response) {
      // Сервер ответил с ошибкой
      console.error('Ошибка сервера:', error.response.status);
      
      if (error.response.status === 401) {
        localStorage.removeItem('token');
        window.location.href = '/login';
      }
    } else if (error.request) {
      // Запрос был отправлен, но нет ответа
      console.error('Нет ответа от сервера');
    } else {
      // Ошибка при настройке запроса
      console.error('Ошибка запроса:', error.message);
    }
    
    return Promise.reject(error);
  }
);

export default api;

Обработка ошибок в Axios

import api from './api';

async function fetchUser(id) {
  try {
    const response = await api.get(`/users/${id}`);
    return response.data;
  } catch (error) {
    if (error.response) {
      // Сервер ответил с ошибкой
      console.error('Статус:', error.response.status);
      console.error('Данные:', error.response.data);
      console.error('Заголовки:', error.response.headers);
      
      // Разные коды ошибок
      switch (error.response.status) {
        case 400:
          throw new Error('Неверный запрос');
        case 401:
          throw new Error('Не авторизован');
        case 403:
          throw new Error('Доступ запрещён');
        case 404:
          throw new Error('Пользователь не найден');
        case 500:
          throw new Error('Ошибка сервера');
        default:
          throw new Error('Неизвестная ошибка');
      }
    } else if (error.request) {
      // Запрос был отправлен, но ответ не получен
      console.error('Нет ответа от сервера');
      throw new Error('Сервер не отвечает');
    } else {
      // Ошибка при настройке запроса
      console.error('Ошибка:', error.message);
      throw error;
    }
  }
}

Отмена запросов (AbortController)

Axios поддерживает отмену запросов через AbortController:

import { useState, useEffect } from 'react';
import api from './api';

function SearchComponent() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);

  useEffect(() => {
    const controller = new AbortController();

    const fetchResults = async () => {
      try {
        const response = await api.get('/search', {
          params: { q: query },
          signal: controller.signal
        });
        setResults(response.data);
      } catch (error) {
        if (error.name === 'CanceledError') {
          console.log('Запрос отменён');
        } else {
          console.error('Ошибка:', error);
        }
      }
    };

    if (query) {
      fetchResults();
    }

    return () => controller.abort(); // Отменяем запрос при размонтировании
  }, [query]);

  return (
    <div>
      <input 
        value={query} 
        onChange={(e) => setQuery(e.target.value)} 
        placeholder="Поиск..."
      />
      <ul>
        {results.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
}

Преимущества:

  1. Отменяет запрос при быстром вводе
  2. Предотвращает race conditions
  3. Экономит трафик и ресурсы

Axios с React Query (идеальная пара)

Axios и React Query отлично работают вместе:

import { useQuery, useMutation } from '@tanstack/react-query';
import api from './api';

// Запрос через useQuery + Axios
function Users() {
  const { data, isLoading, error } = useQuery({
    queryKey: ['users'],
    queryFn: async () => {
      const response = await api.get('/users');
      return response.data;
    }
  });

  // Мутация через useMutation + Axios
  const createUser = useMutation({
    mutationFn: (newUser) => api.post('/users', newUser),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['users'] });
    }
  });

  return (
    <div>
      {isLoading && <p>Загрузка...</p>}
      {error && <p>Ошибка: {error.message}</p>}
      {data && <UserList users={data} />}
      <button onClick={() => createUser.mutate({ name: 'Новый пользователь' })}>
        Добавить
      </button>
    </div>
  );
}

Преимущества:

  1. React Query управляет кешированием и состоянием
  2. Axios управляет HTTP-запросами
  3. Идеальное разделение ответственности

axios vs fetch (сравнение)

Характеристика fetch Axios
Установка Встроенный Требуется npm install
Размер 0 байт ~4kb
JSON по умолчанию ❌ Нет ✅ Да
Ошибки 4xx/5xx ❌ Не бросает ✅ Бросает
Интерсепторы ❌ Нет ✅ Есть
Отмена запросов AbortController Встроенная
Прогресс загрузки ❌ Нет ✅ Есть
Старые браузеры Требует полифилл Работает
Параметры URL Вручную params

Когда использовать Axios

  1. Сложное приложение с множеством запросов
  2. Нужны интерсепторы для токенов и ошибок
  3. Команда привыкла к Axios

Когда использовать fetch

  1. Простое приложение с 2–3 запросами
  2. Нет необходимости в интерсепторах
  3. Хочется минимизировать зависимости

Частые ошибки новичков

Ошибка Почему Исправление
Забывают .data из ответа Ошибка: response.data — объект, response — не объект Всегда используй response.data
Не обрабатывают ошибки ответа (4xx/5xx) Axios бросает ошибки, но их нужно ловить Всегда добавляй try/catch или .catch()
Не используют экземпляр Дублируют baseURL в каждом запросе Создай экземпляр через axios.create()
Забывают отменять запросы Memory leaks и race conditions Используй AbortController
Не используют интерсепторы для токенов Код с токеном дублируется Добавь интерсептор для авторизации

Задание для закрепления (на 1–2 часа)

Создай полноценное приложение «Менеджер задач» с использованием Axios:

  1. Настройка: Создай экземпляр Axios с baseURL к публичному API (JSONPlaceholder)
  2. GET запросы: Загрузи список задач через useEffect и покажи их
  3. POST запрос: Добавь новую задачу с отправкой на сервер
  4. PUT запрос: Обнови статус задачи (выполнена/не выполнена)
  5. DELETE запрос: Удали задачу
  6. Интерсепторы: добавь логгирование всех запросов в консоль и обработку ошибок (показывай тост при ошибке)
  7. Отмена запросов: Отменяй запрос при размонтировании компонента

Дополнительно:

  1. Добавь пагинацию через параметры _page и _limit
  2. Добавь фильтрацию задач по статусу (все/выполненные/активные)

Проверка: убедись, что все CRUD-операции работают, ошибки обрабатываются, а интерсепторы логируют запросы.

Пример выполненного задания

Код выполненного задания скачать с GitHub: (откроется в новой вкладке)Axios в React

Что дальше?

В следующем уроке разберём use-http — лёгкую альтернативу Axios, построенную на хуках. Ты узнаешь, как работать с HTTP-запросами с минимальным кодом, используя декларативный подход на основе React-хуков.

Теги: