HTTP клиент на JavaScript: делаем запросы правильно в Node.js

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: зачем нужен HTTP клиент в Node.js?

В современной веб-разработке невозможно обойтись без взаимодействия с внешними сервисами. Будь то отправка данных на сервер, получение курса валют, работа с REST API или интеграция с облачными платформами — всё это требует умения отправлять HTTP-запросы. В среде Node.js для этого существует несколько подходов: от встроенного модуля http до популярных сторонних библиотек, таких как axios и нативного fetch.

В этой статье мы разберём, как правильно организовать HTTP-клиент на JavaScript (Node.js), какие инструменты выбрать для разных задач и как избежать типичных ошибок. Вы узнаете, как обрабатывать ответы, управлять асинхронностью и писать чистый, поддерживаемый код.

Основные способы создания HTTP запросов в Node.js

Node.js предоставляет разработчику несколько вариантов для работы с HTTP. Рассмотрим три основных: встроенный модуль http, библиотеку axios и нативный fetch.

1. Встроенный модуль http/https

Самый низкоуровневый способ. Он даёт полный контроль над запросом, но требует написания большего количества кода. Подходит для случаев, когда нужно минимизировать зависимости или работать с нестандартными протоколами.

Пример GET-запроса с использованием модуля https:

const https = require('https');

function getUsers() {
  return new Promise((resolve, reject) => {
    https.get('https://jsonplaceholder.typicode.com/users', (res) => {
      let data = '';
      res.on('data', chunk => data += chunk);
      res.on('end', () => resolve(JSON.parse(data)));
    }).on('error', reject);
  });
}

getUsers().then(users => console.log(users[0].name));

Плюсы: нет внешних зависимостей, полный контроль.
Минусы: громоздкий код, необходимость оборачивать в Promise, ручное управление потоками.

2. Библиотека axios

Самая популярная библиотека для HTTP-запросов. Работает как в браузере, так и в Node.js. Поддерживает Promise, перехватчики (interceptors), автоматический парсинг JSON и отмену запросов.

Установка:

npm install axios

Пример POST-запроса с axios:

const axios = require('axios');

async function createPost() {
  try {
    const response = await axios.post('https://jsonplaceholder.typicode.com/posts', {
      title: 'HTTP клиент на JavaScript',
      body: 'Делаем запросы правильно',
      userId: 1
    });
    console.log('Создан пост:', response.data);
  } catch (error) {
    console.error('Ошибка:', error.message);
  }
}

createPost();

Плюсы: простой API, автоматическая обработка JSON, перехватчики, таймауты.
Минусы: требуется установка, размер библиотеки (~14 КБ gzip).

3. Нативный fetch (Node.js 18+)

Начиная с версии Node.js 18, fetch стал встроенной функцией. Это унифицирует код между браузером и сервером. Однако в старых версиях Node.js потребуется полифилл.

Пример с fetch и async/await:

async function getUser(id) {
  const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  const user = await response.json();
  return user;
}

getUser(1).then(user => console.log(user.name));

Плюсы: нативный, не требует установки, современный API.
Минусы: не поддерживается в Node.js < 18, нет встроенного таймаута, требуется ручная проверка статуса.

Правильная обработка ошибок и таймаутов

Одна из самых частых проблем при работе с HTTP-клиентами — игнорирование обработки ошибок. Сеть ненадёжна, сервер может ответить 500-й ошибкой или не ответить вовсе. Рассмотрим, как грамотно обрабатывать такие ситуации.

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

Axios предоставляет удобный механизм через блок catch:

async function fetchData() {
  try {
    const response = await axios.get('/api/data', { timeout: 5000 });
    return response.data;
  } catch (error) {
    if (error.response) {
      // Сервер ответил, но с ошибкой
      console.error('Статус ошибки:', error.response.status);
      console.error('Данные ошибки:', error.response.data);
    } else if (error.request) {
      // Запрос был отправлен, но ответа нет
      console.error('Сервер не ответил:', error.message);
    } else {
      // Ошибка настройки запроса
      console.error('Ошибка запроса:', error.message);
    }
    throw error;
  }
}

Таймауты и повторные попытки

Для критически важных запросов полезно добавлять механизм повторных попыток (retry). Вот пример простой реализации с axios:

async function fetchWithRetry(url, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await axios.get(url, { timeout: 3000 });
      return response.data;
    } catch (error) {
      if (attempt === maxRetries) throw error;
      console.log(`Попытка ${attempt} не удалась, повтор через 1 сек...`);
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }
}

Асинхронность и параллельные запросы

Node.js — асинхронная среда, и умение работать с параллельными запросами критически важно для производительности. Рассмотрим несколько паттернов.

Последовательные запросы

Используйте async/await для последовательного выполнения:

async function getFullUserInfo(userId) {
  const user = await getUser(userId);
  const posts = await getPostsByUser(userId);
  return { user, posts };
}

Параллельные запросы с Promise.all

Если запросы независимы, выполняйте их параллельно:

async function getMultipleUsers(userIds) {
  const promises = userIds.map(id => getUser(id));
  const users = await Promise.all(promises);
  return users;
}

Важно: Promise.all завершится ошибкой, если хотя бы один промис будет отклонён. Если нужно получить результаты всех запросов, даже при ошибках, использу

Блоги

Рекомендаций по книгам