- PVSM.RU - https://www.pvsm.ru -
fetch() позволяет вам делать запросы, схожие с XMLHttpRequest (XHR). Основное отличие заключается в том, что Fetch API использует Promises (Обещания) [1], которые позволяют использовать более простое и чистое API, избегать катастрофического количества callback'ов и необходимости помнить API для XMLHttpRequest.
Fetch API стал доступен пользователям вместе с Service Worker [2]'ами в global скоупе в Chrome 40, однако уже в версии 42 он станет доступен в скоупе window. Разумеется, для всех остальных браузеров, которые не пока ещё не поддерживают fetch [3] существует полифил от GitHub [4], который доступен уже сегодня.
Давайте начнём со сравнения простого примера, реализованного с XMLHttpRequest и fetch. Всё, что мы будем делать в этом примере — сделаем запрос на URL, получим ответ и распарсим его как JSON.
Пример с XMLHttpRequest потребует от нас установить два обработчика событий на success и error, а так же вызвать два метода: open() и send(). Пример из MDN документации [5]:
function reqListener() {
var data = JSON.parse(this.responseText);
console.log(data);
}
function reqError(err) {
console.log('Fetch Error :-S', err);
}
var oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.onerror = reqError;
oReq.open('get', './api/some.json', true);
oReq.send();
Наш fetch запрос будет выглядеть так:
fetch('./api/some.json')
.then(
function(response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' +
response.status);
return;
}
// Examine the text in the response
response.json().then(function(data) {
console.log(data);
});
}
)
.catch(function(err) {
console.log('Fetch Error :-S', err);
});
Первым делом мы проверяем статус ответа и проверяем, успешно ли выполнился запрос (ожидаем 200 статус). Если всё хорошо, то парсим ответ как JSON.
Ответом fetch() является Stream-объект [6]. Это означает, что в результате вызова метода json() мы получим Promise, т.к. чтение из подобного объекта является асинхронным.
В предыдущем примере мы изучили, как можно проверить статус объекта ответа и конвентировать сам ответ в JSON. Остальные метаданные, к которым вы возможно получить доступ (например, заголовки), приведены ниже:
fetch('users.json').then(function(response) {
console.log(response.headers.get('Content-Type'));
console.log(response.headers.get('Date'));
console.log(response.status);
console.log(response.statusText);
console.log(response.type);
console.log(response.url);
});
Когда мы делаем fetch-запрос, ответу будет дан тип «basic», «cors» или «opaque». Эти «типы» указывают на то, с какого ресурса пришли данные и могут быть использованы для того, чтобы определить процесс обработки данных.
Когда запрос сделан на ресурс, находящимся на том же origin (имеется ввиду, что запрос выполняется в рамках одного сайта. прим. пер.), ответ будет содержать тип «базовый» и для такого запроса не будет никаких ограничений.
Если запрос сделан с одного origin'а на другой (кроссдоменный запрос), который, в свою очередь, вернул CORS [7] заголовки, тогда типом будет являться «cors». Объекты с типами «cors» и «basic» почти идентичны, однако «cors» несколько ограничивает метаданные, к которым может быть получен доступ до «Cache-Control», «Content-Language», «Content-Type», «Expires», «Last-Modified», и «Pragma».
Что касается «opaque» — то он приходит в случаях, когда выполняется CORS запрос, но удаленный ресурс не возвращает CORS заголовки. Данный тип запроса не предоставляет доступ данным или заголовку статуса, поэтому мы не имеем возможности судить о результате выполнения запроса. В рамках текущей имплементации fetch() не представляется возможности выполнять CORS запросы из скоупа window, и вот здесь [8] написано почему. Эта функциональность должна быть добавлена, как только Cache API [9] станет доступным из объекта window.
Вы можете определить ожидаемый режим запроса, тем самым фильтруя результаты запросов с неподходящим типом. Режим запроса может быть установлен на следующий:
— “same-origin” успешно выполняется только для запросов на тот же самый origin, все остальные запросы будут отклонены.
— “cors” работает так же, как «same-origin» + добавляет возможность создавать запросы к сторонним сайтам, если они возвращают соответствующие CORS заголовки.
— “cors-with-forced-preflight” работает так же, как «cors», но перед запросом всегда отсылает тестовый запрос [10] на проверку.
— “no-cors” используется, когда необходимо выполнить запрос к origin, который не отсылает CORS заголовки и результатом выполнения является объект с типом «opaque». Как говорилось выше, в данный момент это невозможно в скоупе window.
Чтобы определить режим запроса, добавьте объект опций вторым параметром к запросу и установите «mode» в этом объекте:
fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})
.then(function(response) {
return response.text();
})
.then(function(text) {
console.log('Request successful', text);
})
.catch(function(error) {
log('Request failed', error)
});
Одной из прекрасных особенностей Promise'ов является возможность группировать их в цепочки. Если говорить о них в скоупе fetch(), то они позволяют нам «шарить» логику между запросами.
Если вы работаете с JSON API, вам потребуется проверить статус и распарсить JSON для каждого ответа. Вы можете упростить свой код, определив парсинг статуса и JSON как раздельные функции, которые вернут Promise'ы. Вам останется подумать только об обработке самих данных и, разумеется, исключений.
function status(response) {
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response)
} else {
return Promise.reject(new Error(response.statusText))
}
}
function json(response) {
return response.json()
}
fetch('users.json')
.then(status)
.then(json)
.then(function(data) {
console.log('Request succeeded with JSON response', data);
}).catch(function(error) {
console.log('Request failed', error);
});
Мы определяем функцию, которая проверяет response.status и возвращает результат: Promise.resolve() или Promise.reject(). Это первый вызванный метод в нашей цепочке, и если он успешно завершается(Promise.resolve()), то вызывается следующий за ним метод — fetch(), который, в свою очередь, опять возвращает Promise от response.json(). После этого вызова, в случае удачного выполнения, у нас будет готовый JSON объект. Если парсинг провалится, Promise будет отменен и сработает условие возникновения исключения.
Но самое лучшее здесь — это возможность переиспользовать такой код для всех fetch-запросов в приложении. Такой код проще поддерживать, читать и тестировать.
Уже давно никого не удивишь необходимостью использовать POST метод с передачей параметров в «теле» запроса для работы с API.
Чтобы осуществить такой запрос, мы должны указать соответствующие параметры в объекте настроек fetch():
fetch(url, {
method: 'post',
headers: {
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
},
body: 'foo=bar&lorem=ipsum'
})
.then(json)
.then(function (data) {
console.log('Request succeeded with JSON response', data);
})
.catch(function (error) {
console.log('Request failed', error);
});
Если вы хотите отправить запрос с каким-либо учётными данными (например, с cookie), вам следует установить `credentials` в опциях запроса на «include»:
fetch(url, {
credentials: 'include'
})
Могу ли я отменить fetch() запрос?
В настоящий момент это невозможно, но это активно обсуждается на GitHub
Существует ли полифил?
Да [4]
Почему «no-cors» реализован для service workers, но не для window?
Это было сделано из соображений безопасности. Подробнее можно ознакомиться здесь [8].
Автор: xamd
Источник [11]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/85650
Ссылки в тексте:
[1] Promises (Обещания): http://habrahabr.ru/post/209662/
[2] Service Worker: http://www.html5rocks.com/en/tutorials/service-worker/introduction/
[3] остальных браузеров, которые не пока ещё не поддерживают fetch: http://caniuse.com/#feat=fetch
[4] полифил от GitHub: https://github.com/github/fetch
[5] Пример из MDN документации: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest
[6] Stream-объект: https://streams.spec.whatwg.org/
[7] CORS: http://www.html5rocks.com/en/tutorials/cors/
[8] вот здесь: https://code.google.com/p/chromium/issues/detail?id=457157&q=fetch%20no-cors&colspec=ID%20Pri%20M%20Week%20ReleaseBlock%20Cr%20Status%20Owner%20Summary%20OS%20Modified
[9] Cache API: https://docs.moodle.org/dev/Cache_API
[10] отсылает тестовый запрос: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
[11] Источник: http://habrahabr.ru/post/252941/
Нажмите здесь для печати.