fetch
Метод fetch()
Встроенный метод браузера для HTTP-запросов. Возвращает промис с объектом Response. Само тело ещё не данные: его читают отдельно, чаще всего через res.json(). Этот метод тоже возвращает промис.
fetch(url, {
method, // по умолчанию GET
headers,
body: JSON.stringify(data), // для POST, PUT, PATCH
});
GET
fetch('https://swapi.dev/api/planets/1')
.then(res => res.json())
.then(data => console.log('data', data))
.catch(error => console.error('error', error));
Свойства ответа
Их смотрят в первом .then, до res.json().
res.ok—true, если статус от 200 до 299res.status— код ответа, например200или404res.headers— заголовки ответа
const url = 'https://swapi.dev/api/planets/1';
fetch(url).then(res => {
console.log('ok', res.ok);
console.log('status', res.status);
console.log('headers', res.headers);
return res.json();
});
Статусы 404 и 500 не попадают в .catch. Туда попадают обрыв сети и ошибка разбора тела. Код ответа проверяют сами и при неуспехе пробрасывают ошибку:
fetch(url)
.then(res => {
if (!res.ok) {
throw new Error(String(res.status));
}
return res.json();
})
.then(data => console.log('data', data))
.catch(error => console.log('error', error));
При статусе 400 или 422 сервер часто присылает JSON с пояснением. Его читают до throw: после исключения тело уже не достать. Текст для пользователя обычно лежит в message, а error.message тогда содержит его, а не только к од.
fetch(url)
.then(res => {
return res.json().then(data => {
if (!res.ok) {
throw new Error(data.message ?? String(res.status));
}
return data;
});
})
.then(data => console.log(data))
.catch(error => console.log(error.message));
Сохранение результата
Присваивание внутри .then случается после ответа. Строка сразу после fetch переменную ещё не видит.
const url = 'https://swapi.dev/api/planets/1';
let save = null;
fetch(url)
.then(res => {
if (!res.ok) {
throw new Error(String(res.status));
}
return res.json();
})
.then(data => {
save = data;
console.log(save);
});
save; // null: запрос ещё не завершён
Чтобы отдать данные из функции, из неё возвращают промис. return внутри .then передаёт значение только следующему звену той же цепочки.
const getData = () => {
return fetch('https://swapi.dev/api/planets/1').then(res => {
if (!res.ok) {
throw new Error(String(res.status));
}
return res.json();
});
};
getData().then(data => {
console.log(data);
});
await пишут только внутри async-функции. В обычном скрипте на верхнем уровне будет SyntaxError.
const getPlanet = async () => {
const res = await fetch('https://swapi.dev/api/planets/1');
if (!res.ok) {
throw new Error(String(res.status));
}
return res.json();
};
getPlanet().then(data => console.log(data));
Строка const data = await getPlanet() в обычном скрипте не выполнится. Её оставляют внутри ещё одной async-функции. Сама data видна только там:
const showPlanet = async () => {
const data = await getPlanet();
console.log(data);
};
showPlanet();
Та же строка допустима на верхнем уровне ES-модуля. В браузере у тега скрипта для этого нужен type="module":
<script type="module">
const data = await getPlanet();
console.log(data);
</script>
В среде, где запускается фрагмент кода, включают top-level await в advanced settings. После этого const data = await getPlanet() работает без обёртки.
POST
Тело передают строкой. Для JSON нужен заголовок Content-Type.
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: 'Title of post',
body: 'Post Body',
}),
})
.then(res => {
if (!res.ok) {
throw new Error(String(res.status));
}
return res.json();
})
.then(data => console.log(data))
.catch(error => console.log(error));
Параметры запроса
fetch(url, {
method: 'POST', // GET, POST, PUT, PATCH, DELETE
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
mode: 'cors', // cors, no-cors, same-origin
credentials: 'same-origin', // omit, same-origin, include
cache: 'default', // default, no-cache, reload, force-cache, only-if-cached
});
Чем читать тело
Тело можно прочитать толь ко один раз.
res.json()— JSONres.text()— текстres.blob()— файлres.formData()—FormData