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