Fetch
JavaScript может отправлять сетевые запросы на » target=»_blank»>сервер и подгружать новую информацию по мере необходимости.
Например, мы можем использовать сетевой запрос, чтобы:
Для сетевых запросов из JavaScript есть широко известный термин «AJAX» (аббревиатура от Asynchronous JavaScript And XML). XML мы использовать не обязаны, просто термин старый, поэтому в нём есть это слово. Возможно, вы его уже где-то слышали.
Есть несколько способов делать сетевые запросы и получать информацию с » target=»_blank»>сервера.
Метод fetch() — современный и очень мощный, поэтому начнём с него. Он не поддерживается старыми (можно использовать полифил), но поддерживается всеми современными браузерами.
Браузер сразу же начинает запрос и возвращает промис, который внешний код использует для получения результата.
Процесс получения ответа обычно происходит в два этапа.
Во-первых, promise выполняется с объектом встроенного класса Response в качестве результата, как только » target=»_blank»>сервер пришлёт заголовки ответа.
На этом этапе мы можем проверить статус HTTP-запроса и определить, выполнился ли он успешно, а также посмотреть заголовки, но пока без тела ответа.
Промис завершается с ошибкой, если fetch не смог выполнить HTTP-запрос, например при ошибке сети или если нет такого сайта. HTTP-статусы 404 и 500 не являются ошибкой.
Мы можем увидеть HTTP-статус в свойствах ответа:
Во-вторых, для получения тела ответа нам нужно использовать дополнительный вызов метода.
Response предоставляет несколько методов, основанных на промисах, для доступа к телу ответа в различных форматах:
Например, получим JSON-объект с последними коммитами из репозитория на GitHub:
В качестве примера работы с бинарными данными, давайте запросим и выведем на экран логотип спецификации «fetch» (см. главу Blob, чтобы узнать про операции с Blob ):
Мы можем выбрать только один метод чтения ответа.
Заголовки ответа
Заголовки запроса
Есть список запрещённых HTTP-заголовков, которые мы не можем установить:
Эти заголовки обеспечивают достоверность данных и корректную работу протокола HTTP, поэтому они контролируются исключительно браузером.
POST-запросы
Чаще всего используется JSON.
Например, этот код отправляет объект user как JSON:
Отправка изображения
Итого
Типичный запрос с помощью fetch состоит из двух операторов await :
Методы для получения тела ответа:
Задачи
Получите данные о пользователях GitHub
В песочнице есть тестовый пример.
А если запрос завершается ошибкой или код статуса в ответе отличен от 200, то мы просто возвращаем null в массиве результатов.
Это пример того, как относительно низкоуровневое Promise API может быть полезным, даже если мы в основном используем async/await в коде.
Введение в fetch
fetch() позволяет вам делать запросы, схожие с XMLHttpRequest (XHR). Основное отличие заключается в том, что Fetch API использует Promises (Обещания), которые позволяют использовать более простое и чистое API, избегать катастрофического количества callback’ов и необходимости помнить API для XMLHttpRequest.
Fetch API стал доступен пользователям вместе с Service Worker’ами в global скоупе в Chrome 40, однако уже в версии 42 он станет доступен в скоупе window. Разумеется, для всех остальных браузеров, которые пока ещё не поддерживают fetch существует полифил от GitHub, который доступен уже сегодня.
Простой Fetch запрос
XMLHttpRequest
Fetch
Наш fetch запрос будет выглядеть так:
Первым делом мы проверяем статус ответа и проверяем, успешно ли выполнился запрос (ожидаем 200 статус). Если всё хорошо, то парсим ответ как JSON.
Ответом fetch() является Stream-объект. Это означает, что в результате вызова метода json() мы получим Promise, т.к. чтение из подобного объекта является асинхронным.
Метаданные ответа
В предыдущем примере мы изучили, как можно проверить статус объекта ответа и конвентировать сам ответ в JSON. Остальные метаданные, к которым вы возможно получить доступ (например, заголовки), приведены ниже:
Типы ответа
Когда мы делаем fetch-запрос, ответу будет дан тип «basic», «cors» или «opaque». Эти «типы» указывают на то, с какого ресурса пришли данные и могут быть использованы для того, чтобы определить процесс обработки данных.
Когда запрос сделан на ресурс, находящимся на том же origin (имеется ввиду, что запрос выполняется в рамках одного сайта. прим. пер.), ответ будет содержать тип «базовый» и для такого запроса не будет никаких ограничений.
Если запрос сделан с одного origin’а на другой (кроссдоменный запрос), который, в свою очередь, вернул CORS заголовки, тогда типом будет являться «cors». Объекты с типами «cors» и «basic» почти идентичны, однако «cors» несколько ограничивает метаданные, к которым может быть получен доступ до «Cache-Control», «Content-Language», «Content-Type», «Expires», «Last-Modified», и «Pragma».
Что касается «opaque» — то он приходит в случаях, когда выполняется CORS запрос, но удаленный ресурс не возвращает CORS заголовки. Данный тип запроса не предоставляет доступ данным или заголовку статуса, поэтому мы не имеем возможности судить о результате выполнения запроса. В рамках текущей имплементации fetch() не представляется возможности выполнять CORS запросы из скоупа window, и вот здесь написано почему. Эта функциональность должна быть добавлена, как только Cache API станет доступным из объекта window.
Вы можете определить ожидаемый режим запроса, тем самым фильтруя результаты запросов с неподходящим типом. Режим запроса может быть установлен на следующий:
— “same-origin” успешно выполняется только для запросов на тот же самый origin, все остальные запросы будут отклонены.
— “cors” работает так же, как «same-origin» + добавляет возможность создавать запросы к сторонним сайтам, если они возвращают соответствующие CORS заголовки.
— “cors-with-forced-preflight” работает так же, как «cors», но перед запросом всегда отсылает тестовый запрос на проверку.
— “no-cors” используется, когда необходимо выполнить запрос к origin, который не отсылает CORS заголовки и результатом выполнения является объект с типом «opaque». Как говорилось выше, в данный момент это невозможно в скоупе window.
Чтобы определить режим запроса, добавьте объект опций вторым параметром к запросу и установите «mode» в этом объекте:
Цепочки Promises
Если вы работаете с JSON API, вам потребуется проверить статус и распарсить JSON для каждого ответа. Вы можете упростить свой код, определив парсинг статуса и JSON как раздельные функции, которые вернут Promise’ы. Вам останется подумать только об обработке самих данных и, разумеется, исключений.
Но самое лучшее здесь — это возможность переиспользовать такой код для всех fetch-запросов в приложении. Такой код проще поддерживать, читать и тестировать.
POST запрос
Уже давно никого не удивишь необходимостью использовать POST метод с передачей параметров в «теле» запроса для работы с API.
Чтобы осуществить такой запрос, мы должны указать соответствующие параметры в объекте настроек fetch() :
Посылаем учётные данные через Fetch-запрос
Если вы хотите отправить запрос с каким-либо учётными данными (например, с cookie), вам следует установить `credentials` в опциях запроса на «include»:
Могу ли я отменить fetch() запрос?
В настоящий момент это невозможно, но это активно обсуждается на GitHub
Существует ли полифил?
Да
Почему «no-cors» реализован для service workers, но не для window?
Это было сделано из соображений безопасности. Подробнее можно ознакомиться здесь.
Использование Fetch
Обратите внимание, fetch спецификация отличается от jQuery.ajax() в основном в двух пунктах:
Базовый запрос на получение данных действительно прост в настройке. Взгляните на следующий код:
Здесь мы забираем JSON файл по сети и выводим его содержимое в консоль. Самый простой способ использования fetch() заключается в вызове этой функии с одним аргументом — строкой, содержащей путь к ресурсу, который вы хотите получить — которая возвращает promise, содержащее ответ (объект Response ).
Примечание: Миксин Body имеет подобные методы для извлечения других типов контента; см. раздел Тело.
Fetch-запросы контролируются посредством директивы connect-src (Content Security Policy), а не директивой извлекаемых ресурсов.
Установка параметров запроса
Отправка запроса с учётными данными
Напротив, чтобы быть уверенным, что учётные данные не передаются с запросом, используйте credentials: ‘omit’ :
Отправка данных в формате JSON
При помощи fetch() (en-US) можно отправлять POST-запросы в формате JSON.
Загрузка файла на » target=»_blank»>сервер
Загрузка нескольких файлов на » target=»_blank»>сервер
Обработка текстового файла построчно
Проверка успешности запроса
Составление своего объекта запроса
Заголовки
То же может быть достигнуто путём передачи массива массивов или литерального объекта конструктору:
Содержимое может быть запрошено и извлечено:
Хорошим вариантом использования заголовков является проверка корректности типа контента перед его обработкой. Например:
Защита
С тех пор как заголовки могут передаваться в запросе, приниматься в ответе и имеют различные ограничения в отношении того, какая информация может и должна быть изменена, заголовки имеют свойство guard. Это не распространяется на Web, но влияет на то, какие операции мутации доступны для объекта заголовков.
Объекты ответа
Как вы видели выше, экземпляр Response будет возвращён когда fetch() промис будет исполнен.
Свойства объекта-ответа которые чаще всего используются:
Конструктор Response() принимает два необязательных аргумента — тело для ответа и объект init (аналогичный тому, который принимает Request() (en-US) )
Примечание: Метод error() (en-US) просто возвращает ответ об ошибке. Аналогично, redirect() (en-US) возвращает ответ, приводящий к перенаправлению на указанный URL. Они также относятся только к Service Workers.
Запрос и ответ могут содержать данные тела. Тело является экземпляром любого из следующих типов:
Body примесь определяет следующие методы для извлечения тела (реализованы как для Request так и для Response ). Все они возвращают promise, который в конечном итоге исполняется и выводит содержимое.
Это делает использование нетекстовых данных более лёгким, чем при XMR.
В запросе можно установить параметры для отправки тела запроса:
Параметры request и response (and by extension the fetch() function), по возможности возвращают корректные типы данных. Параметр request также автоматически установит Content-Type в заголовок, если он не был установлен из словаря.
Функция обнаружения
Полифил
Axios или Fetch: чем пользоваться в 2019 году?
Axios — это широко известная JavaScript-библиотека. Она представляет собой HTTP-клиент, основанный на промисах и предназначенный для браузеров и для Node.js. Если вы работали в последние несколько лет JavaScript-программистом, то вы, совершенно определённо, этой библиотекой пользовались. В октябре 2019 года пакет Axios был загружен из npm 25 миллионов раз. Кажется, что будущее Axios безоблачно. Но что если я скажу вам, что Axios — это мёртвый проект. Именно этому было посвящено одно обсуждение на Reddit. А именно, речь идёт о следующем:
Когда библиотека Axios стала популярной, в браузерах не было API, реализующего HTTP-клиент, основанный на промисах. Стандартный интерфейс XML HTTP Request (XHR) был неудобным, работать с ним было тяжело. Разработчики с радостью приняли Axios из-за того, что эта библиотека облегчала им жизнь.
В 2015 вышел API Fetch. Почему же мы, в 2019 году, до сих пор используем Axios? Давайте сравним эти две технологии.
Объём шаблонного кода
▍Fetch
▍Axios
При использовании Fetch приходится иметь дело с двумя промисами. А вот при работе с Axios у нас есть прямой доступ к JSON-результату в свойстве data объекта ответа.
Метод json() миксина Body принимает поток Response и полностью читает его. Он возвращает промис, который разрешается JSON-результатом разбора текста тела запроса.
Ещё больше шаблонного кода в Fetch приходится использовать при работе с POST-запросами.
▍Fetch
▍Axios
Использование Axios позволяет избежать написания больших объёмов шаблонного кода и сделать код чище и понятнее.
Обработка ошибок
▍Fetch
▍Axios
Отсутствующие возможности
Axios умеет следить за ходом выгрузки данных. Fetch это не поддерживает. Это может стать решающим фактором выбора технологии для тех, кто разрабатывает приложение, позволяющее пользователям выгружать на » target=»_blank»>сервер фотографии или видеофайлы.
Альтернативные библиотеки
Вот пара альтернатив Axios и API Fetch:
Итоги
Чем стоит пользоваться в 2019 году? Это зависит от многого. Например, если вам нужно отслеживать прогресс выгрузки материалов на