Введение: зачем нужен 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 завершится ошибкой, если хотя бы один промис будет отклонён. Если нужно получить результаты всех запросов, даже при ошибках, использу