Реализация XMLHttpRequest
и fetch()
отличается в паре моментов, чтобы обеспечить fetch()
лучшее управление запросом и ответом:
- Промисы, возвращаемые from
fetch()
не будут завершаться ошибкой при любом статусе ошибки HTTP (даже HTTP 404 или 500). - Это будет успешно разрешено, если статус
ok
установлен наfalse
. - Это произойдет только с ошибкой сети или если запрос не может быть выполнен.
- По умолчанию
fetch()
не будет отправлять файлы cookie или учетные данные на сервер. - Используя параметр
init
, вы можете указать, как поступать с файлами cookie и учетными данными, уже сохраненными в клиенте (omit
,include
,same-origin
). - С 25 августа 2017 г. спецификация изменила политику учетных данных по умолчанию на
same-origin
.
использование
Первый аргумент forfetch()
— это URL ресурса и, необязательно, второй параметр init
(объект с набором атрибутов запроса):
var fetchResponsePromise = fetch(URL [, init] );
Вы можете получить тот же результат, создав объект Request
, а затем вызвав fetch()
var request = new Request(URL [, init]) var fetchResponsePromise = fetch(request);
Результатом является Promise
, который разрешается в объект Response
. Вы можете связать этот вызов с then()
, чтобы использовать разрешенный ответ, и catch()
, чтобы зафиксировать ошибки в процессе запроса/ответа. Например, это обычный вызов fetch()
для извлечения и анализа данных JSON [https://codepen.io/fraigo/pen/GRKdwdR?editors=1111]:
fetch('https://myhost.com/api',{ credentials: 'same-origin' }) .then(function(response) { // use response.text() to continue with plain text // verify response checking (response.ok) return response.json() }).then(function(jsonData) { console.log('Parsed JSON', jsonData) }).catch(function(ex) { console.error('Error', ex.message) })
Таким образом, после получения response
он преобразуется в объект JSON с помощью response.json().
. Затем можно использовать объект JSON jsonData
. В случае возникновения какой-либо ошибки исключение ex
будет содержать сведения об ошибке. Синтаксис стрелочных функций ES6 еще более понятен:
fetch('https://myhost.com/api',{ credentials: 'same-origin' }) .then(response => response.json()) .then(jsonData => console.log('Parsed JSON', jsonData)) .catch(ex => console.error('Error', ex.message))
Чтобы увидеть разницу, это тот же процесс с использованием XMLHttpRequest [https://codepen.io/fraigo/pen/XWrqyaV?editors=1111].
var httpRequest = new XMLHttpRequest(); httpRequest.onreadystatechange = function(){ if (httpRequest.readyState === XMLHttpRequest.DONE) { if (httpRequest.status === 200) { try { console.log('Response text', httpRequest.responseText); var jsonData=JSON.parse(httpRequest.responseText); console.log('Parsed JSON', jsonData); } catch (e) { console.error("Parse Error", httpRequest.statusText); } } else { console.error("Response Error", httpRequest.statusText); } } }; httpRequest.onerror = function(){ // will fail in HTTP 500 or 404 as well console.error("Request Error"); }; httpRequest.open('GET', 'myhost.com/api'); httpRequest.send();
Основные отличия очевидны. Используя XmlHTTPRequest
, мы имеем:
- Множество точек отказа/исключения, различные способы их обнаружения
- Больше строк кода, не следуйте линейной последовательности
- Один объектдля управления запросом и ответом
С другой стороны, используя fetch():
- Обнаружение одной точки отказа в отклонении обещания.
- Чистый код, затем последовательно
- Различные объекты для управления запросами и ответами (включая заголовки и тело)
В следующих разделах я покажу вам основные концепции основных компонентов Fetch API: Request
, Response
и Headers
.
Запрос
Основным элементом API-интерфейса Javascript Fetch является файл Request
. Основные свойства:
.method
(например, GET, POST и т. д.).headers
(массив изHeader
элементов).credentials
(например, «опустить», «того же происхождения», «включить»).cache
(например, по умолчанию, перезагрузить, без кеша).body
(тело запроса).context
(например, аудио, изображение, iframe и т. д.).mode
(например, cors, no-cors, тот же источник, навигация.)
var request = new Request( 'https://jsonplaceholder.typicode.com/todos/1', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded'}, credentials: 'same-origin', body: 'user=John&[email protected]' } );
Заголовки
Кроме того, вы можете манипулировать заголовками HTTP (как в Request
, так и в Response
) для обычных операций:
.append()
для создания или добавления нового заголовка (заголовки с одинаковым именем).delete()
для удаления значения заголовка.entries()
возвращает итератор для перебора всех заголовков.forEach()
помогает перебирать каждый элемент заголовка.get()
для получения определенного значения заголовка.has()
позволяет проверить, установлено ли имя заголовка.keys()
возвращает итератор для перебора всех имен заголовков
В следующем примере мы настраиваем запрос, используя заголовки request.
var myHeaders = new Headers(); myHeaders.append('Content-Type', 'text/json'); myHeaders.append('Authorization', 'Basic QWxhZGRpbjpPcGVuU2VzYW1l'); var myRequest = new Request('https://myhost.com/auth', {headers: myHeaders, method: 'post'})
Кроме того, вы можете получать и управлять заголовками response:
fetch(myRequest).then(function(response) { var resHeaders = response.headers; if (resHeaders.has('Auth-token')){ var myToken = resHeaders.get('Auth-token'); response.text().then(function(textContent) { resultMsg.innerText = textContent; }); } });
Ответ
Наконец, вы можете обработать Response
множеством опций и методов:
.headers
Объект заголовков, связанный с ответом.ok
Будетtrue
, если ответ был успешным, со статусом HTTP 200-299.status
Код состояния HTTP (например, 200 для успеха, 404 не найдено).statusText
Текст, относящийся к коду состояния (например, ОК для 200, Неавторизовано для 401)- Все методы
Body
для управления содержимым ответа: .text()
A Обещание получить простые текстовые данные.json()
Чтобы получить проанализированные данные JSON в объекте.blob()
Для обработкиBlob
данных (двоичных, необработанных). См. Блоб.arrayBuffer()
Чтобы получить массив необработанных байтов. См. ArrayBuffer.
В следующем примере мы получаем двоичные данные в Blob
и создаем URL-адрес данных для отображения изображения:
fetch('captcha.png', { cache: 'no-cache' }) .then(function(response) { return response.blob(); }).then(function(blob) { const imageURL = URL.createObjectURL(blob); captchaImage.src = imageURL; });
Совместимость
Тем, кому нужна обратная совместимость со старыми браузерами без поддержки .fetch()
, можно использовать Javascript Fetch API polyfill (https://github.com/github/fetch ).
В некоторых случаях вам также может понадобиться поддержка промисов. Для этого случая доступен Promise
полифилл (https://github.com/taylorhakes/promise-polyfill)