HTTP клиент на JavaScript: делаем запросы правильно — от А до Я
В современной веб-разработке взаимодействие с внешними API и серверами — базовая задача. Будь то получение данных о погоде, отправка формы или интеграция с платежным шлюзом, вам понадобится HTTP клиент. В этой статье мы разберем, как создавать HTTP запросы на JavaScript (Node.js) правильно: от выбора инструмента до обработки ошибок и оптимизации. Вы узнаете, как писать надежный и производительный код.
1. Выбор инструмента: нативные возможности vs библиотеки
Node.js предоставляет несколько способов выполнения HTTP запросов. Выбор зависит от сложности задачи и личных предпочтений.
1.1. Встроенный модуль http / https
Это самый низкоуровневый подход. Он дает полный контроль, но требует много кода для простых запросов.
const https = require('https');
function getUsers() {
return new Promise((resolve, reject) => {
const url = 'https://jsonplaceholder.typicode.com/users';
https.get(url, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
try {
resolve(JSON.parse(data));
} catch (e) {
reject(e);
}
});
}).on('error', reject);
});
}
getUsers().then(console.log).catch(console.error);
1.2. Глобальный fetch (с Node.js 18+)
Начиная с версии 18, в Node.js появился нативный fetch, знакомый по браузерам. Это современный и удобный API.
async function getPosts() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Fetch error:', error);
throw error;
}
}
getPosts().then(posts => console.log(posts.slice(0, 2)));
1.3. Популярные библиотеки: axios
axios — самая популярная библиотека для HTTP запросов. Она предоставляет удобный API, поддержку промисов, перехватчики (interceptors) и автоматический парсинг JSON.
const axios = require('axios');
async function createTodo() {
try {
const response = await axios.post('https://jsonplaceholder.typicode.com/todos', {
title: 'Изучить HTTP клиенты',
completed: false,
userId: 1
});
console.log('Создано:', response.data);
return response.data;
} catch (error) {
console.error('Ошибка:', error.response?.data || error.message);
}
}
createTodo();
Итог: Для простых скриптов используйте fetch. Для серьезных проектов с множеством запросов и перехватчиками — axios. Модуль http оставьте для специфических случаев.
2. Основные типы запросов и работа с данными
Разберем, как правильно отправлять GET, POST, PUT и DELETE запросы с помощью axios.
2.1. GET — получение данных
async function getUser(id) {
try {
const { data } = await axios.get(`https://jsonplaceholder.typicode.com/users/${id}`);
return data;
} catch (error) {
throw new Error(`Не удалось получить пользователя ${id}: ${error.message}`);
}
}
2.2. POST — создание ресурса
Передаем данные в теле запроса. Важно указывать тип контента (Content-Type). Axios делает это автоматически для JSON.
async function createUser(userData) {
const response = await axios.post('https://jsonplaceholder.typicode.com/users', userData, {
headers: {
'Content-Type': 'application/json'
}
});
return response.data;
}
2.3. PUT и PATCH — обновление
PUT заменяет ресурс целиком, PATCH — частично.
// Полная замена
async function updateUser(id, userData) {
const { data } = await axios.put(`https://jsonplaceholder.typicode.com/users/${id}`, userData);
return data;
}
// Частичное обновление
async function patchUser(id, partialData) {
const { data } = await axios.patch(`https://jsonplaceholder.typicode.com/users/${id}`, partialData);
return data;
}
2.4. DELETE — удаление
async function deleteUser(id) {
await axios.delete(`https://jsonplaceholder.typicode.com/users/${id}`);
console.log(`Пользователь ${id} удален`);
}
3. Продвинутые техники: перехватчики, таймауты и повторные попытки
Чтобы HTTP клиент был надежным, нужно учитывать пограничные случаи.
3.1. Перехватчики (Interceptors)
Позволяют глобально обрабатывать запросы и ответы. Например, добавлять токен авторизации или логировать ошибки.
// Добавляем токен к каждому запросу
axios.interceptors.request.use(config => {
config.headers.Authorization = `Bearer ${process.env.API_TOKEN}`;
console.log(`[${config.method.toUpperCase()}] ${config.url}`);
return config;
}, error => Promise.reject(error));
// Логируем ответы
axios.interceptors.response.use(
response => response,
error => {
console.error('Ошибка запроса:', error.config?.url, error.message);
return Promise.reject(error);
}
);
3.2. Таймауты
Никогда не ждите ответа бесконечно. Устанавливайте разумный таймаут.
async function fetchWithTimeout(url, timeoutMs = 5000) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetch(url, { signal: controller.signal });
return response.json();
} finally {
clearTimeout(timeout);
}
}
// Для axios
const axiosInstance = axios.create({ timeout: 10000 });
3.3. Повторные попытки (Retry)
При временных ошибках сети полезно автоматически повторять запрос.
async function fetchWithRetry(url, options = {}, retries = 3) {
for (let attempt = 1; attempt <= retries; attempt++) {
try {
const response = await fetch(url, options);
if (response.ok) return response.json();
throw new Error(`HTTP ${response.status}`);
} catch (error) {
if (attempt === retries) throw error;
console.log(`Попытка ${attempt} не удалась. Повтор через ${attempt * 1000}