Выполнение HTTP-запросов в Node.js с помощью node-fetch

Введение Веб-приложению часто требуется взаимодействовать с веб-серверами для получения различных ресурсов. Возможно, вам потребуется извлечь данные или отправить данные на внешний веб-сервер или API. Используя клиентский JavaScript, этого можно достичь с помощью API-интерфейса fetch и функции window.fetch (). В NodeJS несколько пакетов / библиотек могут достичь одного и того же результата. Один из них - пакет node-fetch [https://www.npmjs.com/package/node-fetch]. node-fetch - это легкий модуль, который позволяет нам использовать t

Вступление

Веб-приложению часто требуется взаимодействовать с веб-серверами для получения различных ресурсов. Возможно, вам потребуется извлечь данные или отправить данные на внешний веб-сервер или API.

Используя клиентский JavaScript, этого можно достичь с помощью API-интерфейса fetch и функции window.fetch() . В NodeJS несколько пакетов / библиотек могут достичь одного и того же результата. Один из них - пакет node-fetch

node-fetch - это легкий модуль, который позволяет нам использовать fetch() в NodeJS, с функциональностью, очень похожей на window.fetch() в собственном JavaScript, но с некоторыми отличиями .

Начало работы с node-fetch

Чтобы использовать node-fetch в своем проекте, cd в каталог проекта и запустите:

 $ npm install node-fetch 

Чтобы использовать модуль в коде, используйте:

 const fetch = require('node-fetch'); 

Как упоминалось ранее, функция fetch() node-fetch ведет себя очень аналогично собственной функции window.fetch() . Его подпись:

 fetch(url[, options]); 

Параметр url - это просто прямой URL-адрес ресурса, который мы хотим получить. Это должен быть абсолютный URL-адрес, иначе функция выдаст ошибку. Необязательный options используется, когда мы хотим использовать fetch() для чего-либо, кроме простого GET , но мы поговорим об этом более подробно позже.

Функция возвращает Response который содержит полезные функции и информацию об ответе HTTP, например:

  • text() - возвращает тело ответа в виде строки
  • json() - анализирует тело ответа на объект JSON и выдает ошибку, если тело не может быть проанализировано
  • status и statusText - содержат информацию о коде статуса HTTP
  • ok - равно true если status - это код статуса 2xx (успешный запрос)
  • headers - объект, содержащий заголовки ответа, доступ к конкретному заголовку можно получить с помощью функции get() .

Отправка запросов GET с использованием node-fetch

Есть два распространенных случая получения данных с веб-сервера. Возможно, вы захотите получить текст с веб-сервера, целую веб-страницу или данные с помощью REST API. Пакет node-fetch позволяет вам делать все это.

Создайте каталог для вашего проекта, cd в каталог и инициализируйте проект Node с настройками по умолчанию:

 $ npm init -y 

В каталоге будет создан package.json Затем установите node-fetch как показано выше, и добавьте файл index.js

Получение текста или веб-страниц

Давайте сделаем простой GET на главную страницу Google:

 const fetch = require('node-fetch'); 
 
 fetch('https://google.com') 
 .then(res => res.text()) 
 .then(text => console.log(text)) 

В приведенном выше коде мы загружаем node-fetch а затем загружаем домашнюю страницу Google. Единственный параметр, который мы добавили в fetch() - это URL-адрес сервера, к которому мы отправляем HTTP-запрос. Поскольку node-fetch основан на обещаниях, мы связываем пару функций .then() чтобы помочь нам управлять ответом и данными из нашего запроса.

В этой строке мы ждем ответа от веб-сервера Google и конвертируем его в текстовый формат:

 .then(res => res.text()); 

Здесь ждем результата предыдущего преобразования и выводим его в консоль:

 .then(text => console.log(text)); 

Если мы запустим приведенный выше код из консоли:

 $ node index.js 

Мы получим всю HTML-разметку домашней страницы Google, записанную в консоль:

 <!doctype html> 
 <html itemscope="" itemtype="http://schema.org/WebPage" lang="en-RS"> 
 <head> 
 <meta charset="UTF-8"> 
 <meta content="origin" name="referrer"> 
 <!-- Rest of the page --> 

Получение данных JSON из REST API

Другой распространенный вариант использования node-fetch - получение данных с помощью REST API.

Мы получим поддельные данные пользователя из REST API JSONPlaceholder. Как и раньше, fetch() принимает URL-адрес сервера и ожидает ответа.

Давайте посмотрим, как это работает:

 const fetch = require('node-fetch'); 
 
 fetch('https://jsonplaceholder.typicode.com/users') 
 .then(res => res.json()) 
 .then(json => { 
 console.log("First user in the array:"); 
 console.log(json[0]); 
 console.log("Name of the first user in the array:"); 
 console.log(json[0].name); 
 }) 

Тело ответа HTTP содержит данные в формате JSON, а именно массив, содержащий информацию о пользователях. Имея это в виду, мы использовали .json() , и это позволило нам легко получить доступ к отдельным элементам и их полям.

Запуск этой программы даст нам:

 First element in the array: 
 { 
 id: 1, 
 name: 'Leanne Graham', 
 username: 'Bret', 
 email: ' [email protected] ', 
 address: { 
 street: 'Kulas Light', 
 suite: 'Apt. 556', 
 city: 'Gwenborough', 
 zipcode: '92998-3874', 
 geo: { lat: '-37.3159', lng: '81.1496' } 
 }, 
 phone: '1-770-736-8031 x56442', 
 website: 'hildegard.org', 
 company: { 
 name: 'Romaguera-Crona', 
 catchPhrase: 'Multi-layered client-server neural-net', 
 bs: 'harness real-time e-markets' 
 } 
 } 
 
 Name of the first person in the array: 
 Leanne Graham 

Мы также могли напечатать весь JSON, возвращенный res.json() .

Отправка запросов POST с помощью node-fetch

Мы также можем использовать fetch() для публикации данных вместо их получения. Как мы упоминали ранее, fetch() позволяет добавить дополнительный параметр для выполнения POST к веб-серверу. Без этого необязательного параметра наш запрос по умолчанию GET

Есть много возможных параметров, которые мы можем установить с помощью этого параметра, но единственные, которые мы будем использовать в этой статье, - это method , body и headers .

Эти поля имеют прямое значение: method устанавливает, какой тип HTTP-запроса мы используем (в нашем случае POST body содержит тело / данные нашего запроса, а headers содержат все необходимые заголовки, что в нашем случае просто Content-Type чтобы не было путаницы при анализе нашего запроса.

Полный список опций вы можете найти в документации .

Мы продемонстрируем, как это работает, добавив новый элемент в задачи JSONPlaceholder . Давайте добавим в этот список новый элемент для пользователя с id 123 . Сначала нам нужно создать todo , а затем преобразовать его в JSON при добавлении в поле body

 const fetch = require('node-fetch'); 
 
 let todo = { 
 userId: 123, 
 title: "loren impsum doloris", 
 completed: false 
 }; 
 
 fetch('https://jsonplaceholder.typicode.com/todos', { 
 method: 'POST', 
 body: JSON.stringify(todo), 
 headers: { 'Content-Type': 'application/json' } 
 }).then(res => res.json()) 
 .then(json => console.log(json)); 

Процесс очень похож на GET . Мы вызвали fetch() с соответствующим URL-адресом и установили необходимые параметры, используя необязательный параметр функции fetch() . Мы использовали JSON.stringify() для преобразования нашего объекта в строку в формате JSON перед его отправкой на веб-сервер. Затем, как и при получении данных, мы ждали ответа, конвертировали его в JSON и выводили на консоль.

Запуск кода дает нам результат:

 { 
 userId: 123, 
 title: 'loren impsum doloris', 
 completed: false, 
 id: 201 
 } 

Обработка исключений и ошибок

Наши запросы иногда могут завершаться ошибкой по разным причинам - ошибка, возникающая в функции fetch() , проблемы с Интернетом, внутренние ошибки сервера и другие. Нам нужен способ справиться с этими ситуациями или, по крайней мере, уметь видеть, что они произошли.

Мы можем обрабатывать исключения времени выполнения, добавляя catch() в конец цепочки обещаний. Давайте добавим в нашу программу catch()

 const fetch = require('node-fetch'); 
 
 let todo = { 
 userId: 123, 
 title: "loren impsum doloris", 
 completed: false 
 } 
 
 fetch('https://jsonplaceholder.typicode.com/todos', { 
 method: 'POST', 
 body: JSON.stringify(todo), 
 headers: { 'Content-Type': 'application/json' } 
 }).then(res => res.json()) 
 .then(json => console.log(json)) 
 .catch(err => console.log(err)) 

В идеале вы не должны просто игнорировать и распечатывать ошибки, а вместо этого иметь систему для их обработки.

Мы должны иметь в виду, что если наш ответ имеет код состояния 3xx / 4xx / 5xx, запрос либо не выполнен, либо клиенту необходимо предпринять дополнительные шаги.

А именно, коды состояния HTTP 3xx указывают на то, что клиенту необходимо предпринять дополнительные шаги, коды 4xx указывают на недопустимый запрос, а коды 5xx указывают на ошибки сервера. Все эти коды состояния говорят нам, что наш запрос не был успешным с практической точки зрения.

catch() не будет регистрировать ни один из этих случаев, потому что связь с сервером прошла успешно, т.е. мы сделали запрос и получили ответ успешно. Это означает, что нам нужно предпринять дополнительные шаги, чтобы убедиться, что мы охватили ситуацию, когда связь клиент-сервер была успешной, но мы не получили ни одного из успешных (2xx) кодов состояния HTTP.

Распространенный способ убедиться, что неудачные запросы вызывают ошибку, - создать функцию, которая проверяет HTTP-статус ответа от сервера. В этой функции, если код состояния не указывает на успех, мы можем выдать ошибку, и catch() ее поймает.

Мы можем использовать ранее упомянутое поле ok Response , которое равно true если код состояния равен 2xx.

Посмотрим, как это работает:

 const fetch = require('node-fetch'); 
 
 function checkResponseStatus(res) { 
 if(res.ok){ 
 return res 
 } else { 
 throw new Error(`The HTTP status of the reponse: ${res.status} (${res.statusText})`); 
 } 
 } 
 
 fetch('https://jsonplaceholder.typicode.com/MissingResource') 
 .then(checkResponseStatus); 
 .then(res => res.json()); 
 .then(json => console.log(json)); 
 .catch(err => console.log(err)); 

Мы использовали функцию в начале цепочки обещаний (перед синтаксическим анализом тела ответа), чтобы узнать, столкнулись ли мы с проблемой. Вместо этого вы также можете выдать настраиваемую ошибку.

Опять же, у вас должна быть стратегия обработки подобных ошибок, а не просто вывод на консоль.

Если все прошло, как ожидалось, и код состояния показал успех, программа продолжится, как и раньше.

Заключение

Выполнение запросов к веб-серверам - обычная задача веб-разработки, и в этой статье мы увидели, как мы можем сделать это эффективно, используя node-fetch - библиотеку, которая делает собственный API-интерфейс выборки браузера совместимым с NodeJS.

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

comments powered by Disqus