Fetch API используется для выполнения ajax-запросов, для вызова API или выборки удаленного ресурса или получения HTML-файла с сервера.
Базовый синтаксис Fetch API
Допустим, нужно получить список сообщений из API https://jsonplaceholder.typicode.com/posts. Во-первых, следует передать этот URL в метод fetch()
в качестве аргумента.
fetch('https://jsonplaceholder.typicode.com/posts');
Метод fetch()
возвращает Promise. Поэтому ответы API нужно обрабатывать с использованием then()
и catch()
.
fetch('https://jsonplaceholder.typicode.com/posts')
.then(function (response) {
// API вернул результат
console.log('success!', response);
}).catch(function (err) {
// Что-то пошло не так
console.warn('Ошибка получения.');
console.log(err);
});
Посмотрим на ответ в консоли: сразу можно обратить внимание, в response.body
нет JSON. Это – ReadableStream
.
Fetch API использует потоки. Чтобы получить данные из API в виде объекта JSON, можно использовать оригинальный метод Fetch API: json()
.
fetch('https://jsonplaceholder.typicode.com/posts')
.then(function (response) {
// API вернул результат
return response.json();
}).then(function (data) {
// Это уже JSON
console.log(data);
}).catch(function (err) {
// Что-то пошло не так
console.warn('Ошибка получения.');
console.log(err);
});
Посмотрите, теперь тут нормальный JSON.
Обработка ошибок для Fetch API
Fetch API обрабатывает ошибки с помощью метода catch()
, потому что он возвращает Promise.
Однако, Promise отклоняется и вызывает метод catch()
только в случае сбоя. Если вернулся ответ от сервера, даже в случае с ошибками 404 или 500, будут работать методы then()
.
Чтобы пофиксить такое поведение, можно использовать свойство ok
в response
, который возвращает Promise.
Если у свойства response.ok
значение true
, вернём response.json()
. Если нет, то вернём отклоненный объект Promise и передадим в нём ответ, чтобы вызвать метод catch()
.
fetch('https://jsonplaceholder.typicode.com/postsQQQQ')
.then(function (response) {
// API вернул результат
if (response.ok) {
return response.json();
} else {
console.log('Это не 200OK')
return Promise.reject(response);
}
}).then(function (data) {
// Это уже JSON
console.log(data);
}).catch(function (err) {
// Что-то пошло не так
console.warn('Ошибка получения.');
console.log(err);
});
Так лучше обрабатывать ошибки в методе Fetch.
В этом примере умышленно искажён URL, он вернёт 404 ошибку, чтобы продемонстрировать отклонение Promise вручную для принудительного вызова метода catch()
.
То же самое можно делать с помощью XHR
Обработчик onreadystatechange
в XHR тоже выполняется независимо от того, был ответ успешным или нет. Здесь тоже нужно проверять, находится ли ответ между 200 и 300, прежде чем работать с ним.
xhr.onreadystatechange = function () {
// Вернём, когда работа метода завершится
if (xhr.readyState !== 4) return;
// обработаем ответ
if (xhr.status >= 200 && xhr.status < 300) {
// Ответ нормальный
console.log('success', JSON.parse(xhr.responseText));
} else {
// Ответ плохой
console.log('error', xhr);
}
};
У Fetch API код получился намного чище, сравните.
Создание других типов запросов
По умолчанию Fetch API выполняет GET-запросы. Допустим, нужно сделать POST-запрос для публикации новой статьи через API. Методу fetch()
надо в этом случае передавать второй аргумент, который можно использовать для передачи объекта с параметрами.
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST'
}).then(function (response) {
// API вернул результат
if (response.ok) {
return response.json();
} else {
console.log('Это не 200OK')
return Promise.reject(response);
}
}).then(function (data) {
// Это уже JSON
console.log(data);
}).catch(function (err) {
// Что-то пошло не так
console.warn('Ошибка получения.');
console.log(err);
});
Для определенных типов запросов может понадобиться передавать данные вместе с запросом. Это можно сделать с помощью свойства body в объекте параметров.
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: 'title=' + encodeURIComponent('Заголовок') +
'&body=' + encodeURIComponent('Текст статьи')
}).then(function (response) {
// API вернул результат
if (response.ok) {
return response.json();
} else {
console.log('Это не 200OK')
return Promise.reject(response);
}
}).then(function (data) {
// Это уже JSON
console.log(data);
}).catch(function (err) {
// Что-то пошло не так
console.warn('Ошибка получения.');
console.log(err);
});
Установка заголовков с помощью Fetch API
Еще одна распространенная вещь, которую может потребоваться сделать, установить для запроса заголовки и другие свойства. Это также можно сделать с помощью объекта параметров.
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: 'title=' + encodeURIComponent('Заголовок') +
'&body=' + encodeURIComponent('Текст статьи'),
headers: {
'Content-Type': 'application/json'
},
referrer: 'no-referrer'
}).then(function (response) {
// API вернул результат
if (response.ok) {
return response.json();
} else {
console.log('Это не 200OK')
return Promise.reject(response);
}
}).then(function (data) {
// Это уже JSON
console.log(data);
}).catch(function (err) {
// Что-то пошло не так
console.warn('Ошибка получения.');
console.log(err);
});
Демка
Здесь можно поэкспериментировать с кросс-доменными запросами (CORS).