Fetch API
Давайте рассмотрим оставшуюся часть API, чтобы охватить все возможности.
На заметку:
Заметим: большинство этих возможностей используются редко. Вы можете пропустить эту главу и, несмотря на это, нормально использовать fetch .
Тем не менее, полезно знать, что вообще может fetch , чтобы, когда появится необходимость, вернуться и прочитать конкретные детали.
Нижеследующий список – это все возможные опции для fetch с соответствующими значениями по умолчанию (в комментариях указаны альтернативные значения):
let promise = fetch(url, < method: "GET", // POST, PUT, DELETE, etc. headers: < // значение этого заголовка обычно ставится автоматически, // в зависимости от тела запроса "Content-Type": "text/plain;charset=UTF-8" >, body: undefined, // string, FormData, Blob, BufferSource или URLSearchParams referrer: "about:client", // или "" для того, чтобы не послать заголовок Referer, // или URL с текущего источника referrerPolicy: "strict-origin-when-cross-origin", // no-referrer-when-downgrade, no-referrer, origin, same-origin. mode: "cors", // same-origin, no-cors credentials: "same-origin", // omit, include cache: "default", // no-store, reload, no-cache, force-cache или only-if-cached redirect: "follow", // manual, error integrity: "", // контрольная сумма, например "sha256-abcdef1234567890" keepalive: false, // true signal: undefined, // AbortController, чтобы прервать запрос window: window // null >);
Довольно-таки внушительный список, не так ли?
В главе Fetch мы разобрали параметры method , headers и body .
Опция signal разъяснена в главе в Fetch: прерывание запроса.
Теперь давайте пройдёмся по оставшимся возможностям.
referrer, referrerPolicy
Данные опции определяют, как fetch устанавливает HTTP-заголовок Referer .
Обычно этот заголовок ставится автоматически и содержит URL-адрес страницы, с которой пришёл запрос. В большинстве случаев он совсем неважен, в некоторых случаях, с целью большей безопасности, имеет смысл убрать или укоротить его.
Опция referrer позволяет установить любой Referer в пределах текущего источника или же убрать его.
Чтобы не отправлять Referer , нужно указать значением пустую строку:
fetch('/page', < referrer: "" // не ставить заголовок Referer >);
Для того, чтобы установить другой URL-адрес (должен быть с текущего источника):
fetch('/page', < // предположим, что мы находимся на странице https://javascript.info // мы можем установить любое значение Referer при условии, что оно принадлежит текущему источнику referrer: "https://javascript.info/anotherpage" >);
Опция referrerPolicy устанавливает общие правила для Referer .
Выделяется 3 типа запросов:
- Запрос на тот же источник.
- Запрос на другой источник.
- Запрос с HTTPS to HTTP (с безопасного протокола на небезопасный).
В отличие от настройки referrer , которая позволяет задать точное значение Referer , настройка referrerPolicy сообщает браузеру общие правила, что делать для каждого типа запроса.
- «strict-origin-when-cross-origin» – значение по умолчанию: для «same-origin» отправлять полный Referer , для «cross-origin» отправлять только «origin» , если только это не HTTPS→HTTP запрос, тогда не отправлять ничего.
- «no-referrer-when-downgrade» – всегда отправлять полный Referer , за исключением случаев, когда мы отправляем запрос с HTTPS на HTTP (на менее безопасный протокол).
- «no-referrer» – никогда не отправлять Referer .
- «origin» – отправлять в Referer только текущий источник, а не полный URL-адрес страницы, например, посылать только http://site.com вместо http://site.com/path .
- «origin-when-cross-origin» – отправлять полный Referer для запросов в пределах текущего источника, но для запросов на другой источник отправлять только сам источник (как выше).
- «same-origin» – отправлять полный Referer для запросов в пределах текущего источника, а для запросов на другой источник не отправлять его вообще.
- «strict-origin» – отправлять только значение источника, не отправлять Referer для HTTPS→HTTP запросов.
- «unsafe-url» – всегда отправлять полный URL-адрес в Referer , даже при запросах HTTPS→HTTP .
Вот таблица со всеми комбинациями:
| Значение | На тот же источник | На другой источник | HTTPS→HTTP |
|---|---|---|---|
| «no-referrer» | — | — | — |
| «no-referrer-when-downgrade» | full | full | — |
| «origin» | origin | origin | origin |
| «origin-when-cross-origin» | full | origin | origin |
| «same-origin» | full | — | — |
| «strict-origin» | origin | origin | — |
| «strict-origin-when-cross-origin» или «» (по умолчанию) | full | origin | — |
| «unsafe-url» | full | full | full |
Допустим, у нас есть админка со структурой URL, которая не должна стать известной снаружи сайта.
Если мы отправляем запрос fetch , то по умолчанию он всегда отправляет заголовок Referer с полным URL-адресом нашей админки (исключение – это когда мы делаем запрос от HTTPS в HTTP, в таком случае Referer не будет отправляться).
Например, Referer: https://javascript.info/admin/secret/paths .
Если мы хотим, чтобы другие сайты получали только источник, но не URL-путь, это сделает такая настройка:
fetch('https://another.com/page', < // . referrerPolicy: "origin-when-cross-origin" // Referer: https://javascript.info >);
Мы можем поставить её во все вызовы fetch , возможно, интегрировать в JavaScript-библиотеку нашего проекта, которая делает все запросы и внутри использует fetch .
Единственным отличием в поведении будет то, что для всех запросов на другой источник fetch будет посылать только источник в заголовке Referer (например, https://javascript.info , без пути). А для запросов на наш источник мы продолжим получать полный Referer (это может быть полезно для отладки).
Политика установки Referer (Referrer Policy) – не только для fetch
Политика установки Referer, описанная в спецификации Referrer Policy, существует не только для fetch , она более глобальная.
В частности, можно поставить политику по умолчанию для всей страницы, используя HTTP-заголовок Referrer-Policy , или на уровне ссылки .
mode
Опция mode – это защита от нечаянной отправки запроса на другой источник:
- «cors» – стоит по умолчанию, позволяет делать такие запросы так, как описано в Fetch: запросы на другие сайты,
- «same-origin» – запросы на другой источник запрещены,
- «no-cors» – разрешены только простые запросы на другой источник.
Эта опция может пригодиться, если URL-адрес для fetch приходит от третьей стороны, и нам нужен своего рода «глобальный выключатель» для запросов на другие источники.
credentials
Опция credentials указывает, должен ли fetch отправлять куки и авторизационные заголовки HTTP вместе с запросом.
- «same-origin» – стоит по умолчанию, не отправлять для запросов на другой источник,
- «include» – отправлять всегда, но при этом необходим заголовок Access-Control-Allow-Credentials в ответе от сервера, чтобы JavaScript получил доступ к ответу сервера, об этом говорилось в главе Fetch: запросы на другие сайты,
- «omit» – не отправлять ни при каких обстоятельствах, даже для запросов, сделанных в пределах текущего источника.
cache
По умолчанию fetch делает запросы, используя стандартное HTTP-кеширование. То есть, учитывается заголовки Expires , Cache-Control , отправляется If-Modified-Since и так далее. Так же, как и обычные HTTP-запросы.
Настройка cache позволяет игнорировать HTTP-кеш или же настроить его использование:
- «default» – fetch будет использовать стандартные правила и заголовки HTTP кеширования,
- «no-store» – полностью игнорировать HTTP-кеш, этот режим становится режимом по умолчанию, если присутствуют такие заголовки как If-Modified-Since , If-None-Match , If-Unmodified-Since , If-Match , или If-Range ,
- «reload» – не брать результат из HTTP-кеша (даже при его присутствии), но сохранить ответ в кеше (если это дозволено заголовками ответа);
- «no-cache» – в случае, если существует кешированный ответ – создать условный запрос, в противном же случае – обычный запрос. Сохранить ответ в HTTP-кеше,
- «force-cache» – использовать ответ из HTTP-кеша, даже если он устаревший. Если же ответ в HTTP-кеше отсутствует, сделать обычный HTTP-запрос, действовать как обычно,
- «only-if-cached» – использовать ответ из HTTP-кеша, даже если он устаревший. Если же ответ в HTTP-кеше отсутствует, то выдаётся ошибка. Это работает, только когда mode установлен в «same-origin» .
redirect
Обычно fetch прозрачно следует HTTP-редиректам, таким как 301, 302 и так далее.
Это можно поменять при помощи опции redirect :
- «follow» – стоит по умолчанию, следовать HTTP-редиректам,
- «error» – ошибка в случае HTTP-редиректа,
- «manual» – не следовать HTTP-редиректу, но установить адрес редиректа в response.url , а response.redirected будет иметь значение true , чтобы мы могли сделать перенаправление на новый адрес вручную.
integrity
Опция integrity позволяет проверить, соответствует ли ответ известной заранее контрольной сумме.
Как описано в спецификации, поддерживаемыми хеш-функциями являются SHA-256, SHA-384 и SHA-512. В зависимости от браузера, могут быть и другие.
Например, мы скачиваем файл, и мы точно знаем, что его контрольная сумма по алгоритму SHA-256 равна «abcdef» (разумеется, настоящая контрольная сумма будет длиннее).
Мы можем добавить это в настройку integrity вот так:
fetch('http://site.com/file', < integrity: 'sha256-abcdef' >);
Затем fetch самостоятельно вычислит SHA-256 и сравнит его с нашей строкой. В случае несоответствия будет ошибка.
keepalive
Опция keepalive указывает на то, что запрос может «пережить» страницу, которая его отправила.
Например, мы собираем статистические данные о том, как посетитель ведёт себя на нашей странице (на что он кликает, части страницы, которые он просматривает), для анализа и улучшения интерфейса.
Когда посетитель покидает нашу страницу – мы хотим сохранить собранные данные на нашем сервере.
Для этого мы можем использовать событие window.onunload :
window.onunload = function() < fetch('/analytics', < method: 'POST', body: "statistics", keepalive: true >); >;
Обычно, когда документ выгружается, все связанные с ним сетевые запросы прерываются. Но настройка keepalive указывает браузеру выполнять запрос в фоновом режиме даже после того, как пользователь покидает страницу. Поэтому эта опция обязательна, чтобы такой запрос удался.
У неё есть ряд ограничений:
- Мы не можем посылать мегабайты: лимит тела для запроса с keepalive – 64кб.
- Если мы собираем больше данных, можем отправлять их регулярно, «пакетами», тогда на момент последнего запроса в onunload их останется немного.
- Этот лимит распространяется на все запросы с keepalive . То есть, мы не можем его обойти, послав 100 запросов одновременно – каждый по 64Кбайт.
- Обычно сервер посылает пустой ответ на такие запросы, так что это не является проблемой.
Глобальная функция fetch()
Глобальный метод fetch() запускает процесс извлечения ресурса из сети. Возвращает promise, содержащий Response объект (ответ на запрос).
Промис fetch() завершается TypeError , если возникает сетевая ошибка, хотя обычно это означает проблему с доступами или аналогичную ей. Для успешного завершения fetch() достаточно удостовериться в том, что промис выполнен и что свойство Response.ok (en-US) имеет значение true . HTTP статус 404 не является сетевой ошибкой.
Метод fetch() контролируется директивой connect-src directive of Content Security Policy (en-US) (политика безопасности контента), а не директивой ресурсов, которые извлекает.
Примечание: Аргументы метода fetch() идентичны аргументам Request() (en-US) конструктора.
Синтаксис
Promise fetch(input[, init]);
Аргументы
Определяет желаемый для получения ресурс. Это может быть:
- USVString (строка), содержащая прямую URL ссылку на ресурс. Некоторые браузеры принимают blob: и data: , как схемы.
- Request объект (объект ответа).
Объект с опциями, содержащий пользовательские настройки, которые вы желаете применить к запросу. Возможные варианты:
- method : Метод запроса, например, GET , POST .
- headers : Заголовки, содержащиеся в объекте Headers (en-US) или в объекте литерале с побитовыми значениями ( ByteString ).
- body : Тело запроса, которое может быть: Blob , BufferSource , FormData , URLSearchParams , или USVString объектами. Обратите внимание, что GET или HEAD запрос не может иметь тела.
- mode : Режим, например, cors , no-cors или same-origin .
- credentials : Полномочия: omit , same-origin или include . Для автоматической отправки куки для текущего домена, эта опция должна быть указана. Начиная с Chrome 50, это свойство также принимает экземпляр класса FederatedCredential (en-US) или PasswordCredential (en-US).
- cache : Режим кеширования запроса default , no-store , reload , no-cache , force-cache или only-if-cached .
- redirect : Режим редиректа: follow (автоматически переадресовывать), error (прерывать перенаправление ошибкой) или manual (управлять перенаправлениями вручную). В Chrome по дефолту стоит follow (ранее, в Chrome 47, стояло manual ).
- referrer : USVString , определяющая no-referrer , client или a URL. Дефолтное значение — client .
- referrerPolicy : Определяет значение HTTP заголовка реферера. Может быть: no-referrer , no-referrer-when-downgrade , origin , origin-when-cross-origin , unsafe-url .
- integrity : Содержит значение целостности субресурсов (subresource integrity (en-US)) запроса (например, sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE= ).
- keepalive : Эта опция может быть использована, чтобы разрешить запросу «пережить» страницу. Получение ресурсов с флагом keepalive — это альтернатива Navigator.sendBeacon() API.
- signal : Экземпляр объекта AbortSignal ; позволяет коммуницировать с fetch запросом и, если нужно, отменять его с помощью AbortController .
Возвращаемое значение
Исключения
Тип Описание AbortError Запрос был отменён (используя AbortController.abort() ). TypeError Начиная с версии Firefox 43, fetch() завершится ошибкой TypeError , если URL имеет такие полномочия, как http://user:password@example.com . Пример
В нашем Fetch Request примере (см. Fetch Request live) мы создаём новый объект Request (запроса), используя релевантный конструктор, а затем получаем его вызовом fetch() . Так как запрашиваемый ресурс — изображение, для того, чтобы присвоить ему подходящий MIME тип и обработать должным образом, мы применяем к ответу метод Body.blob() (en-US), после чего создаём для него Object URL и передаём её в элемент .
var myImage = document.querySelector("img"); var myRequest = new Request("flowers.jpg"); fetch(myRequest) .then(function (response) return response.blob(); >) .then(function (response) var objectURL = URL.createObjectURL(response); myImage.src = objectURL; >);
В нашем Fetch with init then Request примере (см. Fetch Request init live) мы делаем тоже самое, за исключением того, что передаём в качестве аргумента для fetch() объект init:
var myImage = document.querySelector('img'); var myHeaders = new Headers(); myHeaders.append('Content-Type', 'image/jpeg'); var myInit = method: 'GET', headers: myHeaders, mode: 'cors', cache: 'default' >; var myRequest = new Request('flowers.jpg'); fetch(myRequest,myInit).then(function(response) . >);
Обратите внимание, что объект init в качестве аргумента можно передать и в конструктор Request для получения аналогичного результата, например:
var myRequest = new Request("flowers.jpg", myInit);
Допустимо использования объекта литерала в качестве headers в init .
var myInit = method: "GET", headers: "Content-Type": "image/jpeg", >, mode: "cors", cache: "default", >; var myRequest = new Request("flowers.jpg", myInit);
Спецификации
Specification Fetch Standard
# fetch-methodСовместимость с браузерами
BCD tables only load in the browser
Смотрите также
Found a content problem with this page?
- Edit the page on GitHub.
- Report the content issue.
- View the source on GitHub.
This page was last modified on 7 дек. 2023 г. by MDN contributors.
Your blueprint for a better internet.
MDN
Support
- Product help
- Report an issue
Our communities
Developers
- Web Technologies
- Learn Web Development
- MDN Plus
- Hacks Blog
- Website Privacy Notice
- Cookies
- Legal
- Community Participation Guidelines
Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
Portions of this content are ©1998– 2024 by individual mozilla.org contributors. Content available under a Creative Commons license.Выполнение HTTP-запросов в Node.js с помощью node-fetch
Веб-приложению часто требуется взаимодействовать с веб-серверами для получения различных ресурсов. Возможно, вам потребуется извлечь данные или отправить данные на внешний веб-сервер или API.
Используя клиентский JavaScript, этого можно достичь с помощью API fetch и функции window.fetch() . В NodeJS несколько пакетов / библиотек могут достичь одного и того же результата. Один из них — node-fetch .
node-fetch — это небольшой модуль, который позволяет нам использовать функцию fetch() в NodeJS, с функциональностью, очень похожей на нативный window.fetch() , но с некоторыми отличиями:
node-fetch/v3-LIMITS.md at master · node-fetch/node-fetch · GitHub
A light-weight module that brings Fetch API to Node.js — node-fetch/node-fetch
https://github.com/node-fetch/node-fetch/blob/master/docs/v3-LIMITS.md
Начало работы с node-fetch
Чтобы использовать node-fetch в своем проекте, перейдите в каталог проекта и выполните:
npm install node-fetchЧтобы использовать модуль в коде, используйте:
var fetch = require('node-fetch');Как упоминалось ранее, функция fetch() в модуле node-fetch ведет себя очень похоже на window.fetch() . Его сигнатура:
fetch(url[, options])Параметр url просто прямой URL ресурса который мы хотим запросить. Это должен быть абсолютный URL, иначе функция выдаст ошибку. Необязательный параметр options используется, когда мы хотим использовать что-либо, кроме простого GET запроса, но мы поговорим об этом более подробно позже.
Функция возвращает объект Response , содержащий полезные функции и информацию об ответе HTTP, например:
- text() — возвращает тело ответа в виде строки
- json() — анализирует тело ответа на объект JSON и выдает ошибку, если тело не может быть проанализировано
- status и statusText — содержат информацию о коде статуса HTTP
- ok — равно true , если status это код состояния 2xx (успешный запрос)
- headers — объект, содержащий заголовки ответа, к определенному заголовку можно получить доступ с помощью функции get() .
Отправка запросов GET с использованием node-fetch
Есть два распространенных случая получения данных с веб-сервера. Возможно, вы захотите получить текст с веб-сервера, целую веб-страницу или данные с помощью REST API. Пакет node-fetch позволяет все это сделать.
Создайте каталог для вашего проекта и инициализируйте проект Node с настройками по умолчанию:
npm init -yЭто создаст файл package.json в каталоге. Затем установите node-fetch , как показано выше, и добавьте файл index.js .
Получение текста или веб-страниц
Сделаем простой GET запрос на главную страницу Google:
var 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, зарегистрированную в консоли:
Получение данных JSON из REST API
Другой распространенный вариант использования модуля node-fetch — получение данных с помощью REST API.
Мы получим поддельные данные пользователя из REST API JSONPlaceholder. Как и раньше, функция fetch() принимает URL-адрес сервера и ожидает ответа.
Давайте посмотрим, как это работает:
var 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: 'Sincere@april.biz', 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 .
Давайте добавим новый элемент в список задач JSONPlaceholder. Давайте добавим в этот список новый элемент для пользователя, у которого id равно 123 . Сначала нам нужно создать объект todo , а затем преобразовать его в JSON при добавлении в поле body :
var fetch = require('node-fetch'); var 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 перед его отправкой на веб-сервер с помощью JSON.stringify() . Затем, как и при получении данных, мы ждали ответа, конвертировали его в JSON и выводили на консоль.
Запуск кода дает нам результат:
Обработка исключений и ошибок
Наши запросы иногда могут завершаться неудачно по разным причинам — из-за ошибки в функции fetch() , проблем с Интернетом, внутренних ошибок сервера и других. Нам нужен способ справиться с этими ситуациями или, по крайней мере, уметь видеть, что они произошли.
Мы можем обрабатывать исключения выполнения catch() , добавляя их в конец цепочки обещаний. Давайте добавим простую функцию catch() в нашу программу выше:
var fetch = require('node-fetch'); var 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.
Посмотрим, как это работает:
var fetch = require('node-fetch'); function checkResponseStatus(res) < if(res.ok)< return res >else < throw new Error(`The HTTP status of the reponse: $($)`) > > 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-интерфейс fetch из браузера совместимым с NodeJS.
В дополнение к этому мы также рассмотрели, как обрабатывать ошибки, которые могут возникнуть с HTTP-запросами.
Обходим иммитации модулей
Jest позволяет имитировать целые модули. Это полезно, когда нужно протестировать, что ваш код корректно вызывает функции из других модулей. Однако иногда может возникать необходимость использовать лишь часть тестового модуля в тестовом файле, и в этом случае уже нужно получить доступ к исходной реализации, а не только к мок версии.
Рассмотрим пример теста для функции createUser :
createUser.js
import fetch from 'node-fetch'; export const createUser = async () => const response = await fetch('https://website.com/users', method: 'POST'>); const userId = await response.text(); return userId; >;C помощью «заглушки» fetch можно проверить, вызывается ли оригинальная функция, не создавая при этом сетевой запрос. Однако возвращаемое значение функции fetch нужно также сымитировать, используя класс Response (обёрнутый в Promise ). Изначально, тест может выглядеть следующим образом:
jest.mock('node-fetch'); import fetch, Response> from 'node-fetch'; import createUser> from './createUser'; test('createUser calls fetch with the right args and returns the user id', async () => fetch.mockReturnValue(Promise.resolve(new Response('4'))); const userId = await createUser(); expect(fetch).toHaveBeenCalledTimes(1); expect(fetch).toHaveBeenCalledWith('https://website.com/users', method: 'POST', >); expect(userId).toBe('4'); >);Однако, если вы запустите данный тест, функция createUser вернёт ошибку: TypeError: response.text is not a function . Это происходит потому, что класс Response из библиотеки node-fetch был сымитирован (вызов jest.mock в начале файла) и ведёт себя по-другому.
Для решения этой проблемы используйте вспомогательную функцию jest.requireActual . Чтобы тест заработал, добавьте следующие изменения в тестовом файле:
// BEFORE jest.mock('node-fetch'); import fetch, Response> from 'node-fetch';// AFTER jest.mock('node-fetch'); import fetch from 'node-fetch'; const Response> = jest.requireActual('node-fetch');Теперь, вместо имитированного, мы используем настоящий класс Response из node-fetch . А это значит, что тест должен выполниться успешно.