HTTP клиент на JavaScript: делаем запросы правильно в Node.js
Современная веб-разработка немыслима без взаимодействия с удалёнными серверами. Будь то получение данных с REST API, отправка форм или загрузка файлов — HTTP-запросы лежат в основе любой интеграции. Если вы разрабатываете на Node.js, то у вас есть несколько мощных инструментов для создания HTTP-клиента. В этой статье мы разберём, как делать запросы правильно: от встроенных модулей до популярных библиотек, с акцентом на обработку ошибок, таймауты и читаемость кода.
Мы рассмотрим три основных подхода: встроенный модуль http/https, современный fetch (доступный в Node.js 18+) и легендарную библиотеку axios. Для каждого подхода вы найдёте практические примеры и рекомендации.
1. Встроенный модуль http/https: классика жанра
Node.js с самого начала включает модули http и https для работы с сетевыми запросами. Это самый низкоуровневый способ, который даёт полный контроль над процессом. Однако он требует больше кода для обработки ответа.
Пример GET-запроса с использованием модуля https:
const https = require('https');
function getUsers() {
return new Promise((resolve, reject) => {
const options = {
hostname: 'jsonplaceholder.typicode.com',
path: '/users',
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
};
const req = https.request(options, (res) => {
let data = '';
// Собираем данные по частям
res.on('data', (chunk) => {
data += chunk;
});
// Когда ответ полностью получен
res.on('end', () => {
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(JSON.parse(data));
} else {
reject(new Error(`HTTP Error: ${res.statusCode}`));
}
});
});
// Обработка ошибок сети
req.on('error', (err) => {
reject(err);
});
// Таймаут на случай зависания
req.setTimeout(5000, () => {
req.destroy();
reject(new Error('Request timeout'));
});
req.end();
});
}
// Использование
getUsers()
.then(users => console.log('Users:', users.length))
.catch(err => console.error('Error:', err.message));
Плюсы:
- Не требует установки дополнительных пакетов.
- Полный контроль над каждым этапом соединения.
Минусы:
- Много шаблонного кода.
- Ручная обработка чанков и сборка тела ответа.
- Неудобная работа с промисами без обёртки.
Этот подход оправдан, если вы пишете библиотеку для работы с сетью или вам нужна максимальная производительность без лишних зависимостей. В остальных случаях лучше использовать более высокоуровневые решения.
2. Fetch API: современный стандарт
Начиная с Node.js 18, fetch стал встроенной функцией, что сделало его основным инструментом для HTTP-запросов. Он основан на промисах и имеет чистый, интуитивно понятный синтаксис.
Пример POST-запроса с fetch:
async function createPost() {
const url = 'https://jsonplaceholder.typicode.com/posts';
const newPost = {
title: 'HTTP клиент на JavaScript',
body: 'Делаем запросы правильно',
userId: 1
};
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(newPost)
});
// Проверяем статус ответа
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('Created post ID:', data.id);
return data;
} catch (error) {
console.error('Fetch error:', error.message);
throw error;
}
}
createPost();
Пример с таймаутом и обработкой ошибок:
async function fetchWithTimeout(url, options = {}, timeout = 5000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
...options,
signal: controller.signal
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
throw new Error('Request was aborted (timeout)');
}
throw error;
} finally {
clearTimeout(timeoutId);
}
}
// Использование
fetchWithTimeout('https://api.example.com/data', {}, 3000)
.then(data => console.log(data))
.catch(err => console.error('Error:', err.message));
Плюсы:
- Встроен в Node.js (18+), не требует установки.
- Промис-ориентированный, лаконичный синтаксис.
- Поддержка AbortController для отмены запросов.
Минусы:
- Нет автоматической обработки ошибок (HTTP статусы 4xx/5xx не вызывают reject).
- Нет встроенной поддержки прогресса загрузки.
- В старых версиях Node.js (до 18) требуется полифилл.
3. Axios: мощный и удобный инструмент
Библиотека axios остаётся одним из самых популярных HTTP-клиентов для Node.js. Она предоставляет удобный API, автоматическую трансформацию JSON, интерцепторы и множество других полезных функций.
Установка:
npm install axios
Базовый GET-запрос с обработкой ошибок:
const axios = require('axios');
async function fetchUserData(userId) {
try {
const response = await axios.get(`https://jsonplaceholder.typicode.com/users/${userId}`);
console.log('User:', response.data.name);
return response.data;
} catch (error) {
if (error.response) {
// Сервер ответил с кодом ошибки
console.error('Server error:', error.response.status, error.response.data);
} else if (error.request) {
// Запрос был отправлен, но ответа нет
console.error('No response received:', error.message);
} else {
// Ошибка при настройке запроса
console.error('Request setup error:', error.message);
}
throw error;
}
}
fetchUser