Back

Получение данных из API в Node.js

Получение данных из API в Node.js

Если вы frontend-разработчик, пишущий код на Node.js, вы, вероятно, по привычке тянетесь к Axios или задаётесь вопросом, нужен ли вам всё ещё node-fetch. Сегодня ответ проще, чем вы могли бы подумать: современный Node.js имеет стабильный встроенный API fetch, и для большинства случаев использования этого вполне достаточно.

Вот что вам нужно знать, чтобы делать чистые и надёжные серверные HTTP-запросы сегодня.

Ключевые выводы

  • Современный Node.js поставляется с глобальным API fetch на базе undici — никаких пакетов устанавливать не нужно.
  • fetch не выбрасывает исключения при HTTP-ошибках типа 404 или 500. Всегда проверяйте response.ok перед чтением тела ответа.
  • Используйте AbortSignal.timeout() для таймаутов запросов вместо ручной настройки AbortController.
  • Для высоконагруженных сценариев с повторяющимися запросами к одному источнику используйте Pool из undici для повторного использования соединений.
  • Предпочитайте нативный fetch вместо Axios в проектах только для Node, чтобы сохранить список зависимостей минимальным.

API Fetch в Node.js стабилен и встроен

Начиная с Node.js 18, fetch доступен глобально без необходимости импорта. Он был помечен как экспериментальный в v18, затем стабилизирован в v21. Под капотом он работает на undici — HTTP-клиенте, который обеспечивает реализацию fetch в Node — и повторяет браузерный Fetch API, который вы уже знаете.

Никакой установки. Никакого require('node-fetch'). Просто fetch().

const response = await fetch("https://api.github.com/users/nodejs/repos", {
  headers: { "User-Agent": "my-app" },
})

if (!response.ok) {
  throw new Error(`HTTP error: ${response.status}`)
}

const repos = await response.json()
console.log(repos.map((r) => r.name))

Важно понимать: fetch не выбрасывает исключения при HTTP-ошибках типа 404 или 500. Он выбрасывает исключения только при сетевых сбоях. Всегда проверяйте response.ok или response.status перед чтением тела ответа.

Выполнение POST-запросов с помощью API Fetch в Node.js

Отправка данных выполняется просто. Установите method, добавьте заголовок Content-Type и сериализуйте ваши данные:

const response = await fetch("https://api.example.com/posts", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ title: "Hello", body: "World" }),
})

if (!response.ok) {
  throw new Error(`HTTP error: ${response.status}`)
}

const data = await response.json()

Для загрузки FormData полностью пропустите заголовок Content-Typefetch устанавливает его автоматически с правильной границей multipart.

Обработка таймаутов с помощью AbortSignal

В самом вызове fetch нет встроенной опции таймаута, но AbortSignal.timeout() делает это элегантно:

const response = await fetch("https://api.example.com/data", {
  signal: AbortSignal.timeout(5000), // 5 секунд
})

Если запрос превышает лимит, он прерывается. Для простого случая не требуется ручная настройка AbortController.

Для более сложных сценариев — например, если вы хотите отменить запрос на основе действия пользователя и установить таймаут — вы можете комбинировать AbortController с AbortSignal.any():

const controller = new AbortController()

const response = await fetch("https://api.example.com/data", {
  signal: AbortSignal.any([
    controller.signal,
    AbortSignal.timeout(5000),
  ]),
})

// Вызовите controller.abort() в другом месте для ручной отмены

Когда использовать Undici напрямую

Для большинства API-запросов в Node.js глобальный fetch — правильный инструмент. Но если вы делаете много запросов к одному источнику — например, многократно обращаетесь к внутреннему сервису — Pool из undici даёт вам повторное использование соединений и более тонкий контроль.

import { Pool } from "undici"

const pool = new Pool("https://internal-api.example.com", {
  connections: 10,
})

const { statusCode, body } = await pool.request({
  path: "/data",
  method: "GET",
})

const data = await body.json()

Обратите внимание, что pool.request() возвращает body, который является читаемым потоком, а не объектом Response. Вам нужно явно его обработать — например, с помощью body.json() или body.text().

Используйте undici напрямую, когда вам нужен продвинутый пулинг, эффективная потоковая передача больших ответов или максимальная пропускная способность в критичном к производительности коде.

Fetch в Node.js против Axios: что использовать?

Нативный FetchAxios
Требуется установкаНетДа
Совместим с браузеромДаДа
Автоматический парсинг JSONНет (вызов .json())Да
Перехватчики (Interceptors)ВручнуюВстроены
Выбрасывает исключения при HTTP-ошибкахНетДа
Опция таймаутаAbortSignalВстроена

Axios остаётся надёжным выбором, если вам нужны перехватчики, автоматический парсинг JSON или согласованное поведение в браузере и Node в одной кодовой базе. Но если вы пишете код только для Node и не нуждаетесь в этих дополнениях, нативный fetch сохраняет ваш список зависимостей чистым.

Избегайте node-fetch для новых проектов. Это было правильное решение до Node 18, но теперь оно избыточно для любой поддерживаемой версии Node.js.

Заключение

Для серверных HTTP-запросов в современном Node.js начните со встроенного fetch. Он стабилен, знаком и не требует ничего дополнительного. Добавьте AbortSignal.timeout() для таймаутов, проверяйте response.ok на наличие ошибок и обращайтесь к Pool из undici только когда этого требует производительность. Держите Axios в своём инструментарии, если вам действительно нужны его высокоуровневые функции — но не устанавливайте его по умолчанию.

Часто задаваемые вопросы

Да. Глобальный API fetch был представлен как экспериментальный в Node.js 18 и стал стабильным в Node.js 21. Он работает на undici и не требует дополнительных пакетов. Любая поддерживаемая в настоящее время версия Node.js включает его из коробки.

По дизайну fetch отклоняет промис только при сбоях на сетевом уровне, таких как ошибки разрешения DNS или потеря соединения. HTTP-коды ошибок статуса, такие как 404 или 500, считаются валидными ответами. Вы должны самостоятельно проверить response.ok или response.status перед обработкой тела ответа.

Да, конфликта нет. Некоторые команды используют нативный fetch для простых запросов и Axios там, где им нужны перехватчики или автоматическое выбрасывание ошибок. Тем не менее, смешивание HTTP-клиентов добавляет сложность, поэтому выберите один в качестве основного и используйте другой только когда нужны его специфические функции.

Используйте undici напрямую, когда вам нужен пулинг соединений, детальный контроль над HTTP-соединениями или максимальная пропускная способность для повторяющихся запросов к одному источнику. Для типичных API-вызовов, где простота важнее чистой производительности, глобального fetch достаточно.

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay