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