Пошук уроків, статей та іншого контенту
Навчитеся налаштовувати метод, заголовки, параметри та інші опції fetch-запиту.
fetch()Функція fetch() приймає URL і необов’язковий об’єкт параметрів:
fetch(url, options);Об’єкт options дає змогу налаштувати:
HTTP-метод;
заголовки;
тіло запиту;
облікові дані та cookies;
режим CORS;
кешування;
перенаправлення;
скасування запиту;
інші параметри мережевої взаємодії.
Наприклад:
const response = await fetch("/api/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify({
name: "Олена",
email: "olena@example.com"
})
});За замовчуванням fetch() використовує метод GET.
const response = await fetch("/api/products");Такий самий запит можна записати явно:
const response = await fetch("/api/products", {
method: "GET"
});Для інших операцій використовуйте властивість method:
await fetch("/api/products", {
method: "POST"
});
await fetch("/api/products/42", {
method: "PUT"
});
await fetch("/api/products/42", {
method: "PATCH"
});
await fetch("/api/products/42", {
method: "DELETE"
});Найчастіше методи використовують так:
GET — отримати дані;
POST — створити ресурс або виконати операцію;
PUT — повністю замінити ресурс;
PATCH — частково змінити ресурс;
DELETE — видалити ресурс.
Назви методів зазвичай записують великими літерами, хоча значення є рядком і технічно може мати інший регістр.
Заголовки передають додаткову інформацію про запит. Їх задають у властивості headers.
const response = await fetch("/api/profile", {
headers: {
"Accept": "application/json",
"Authorization": "Bearer token-123"
}
});Content-TypeContent-Type описує формат тіла запиту.
Для JSON використовуйте:
headers: {
"Content-Type": "application/json"
}Для HTML-форми:
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}Для файлів або набору даних FormData заголовок Content-Type зазвичай не потрібно встановлювати вручну. Браузер сам додасть правильне значення з boundary.
Заголовок Accept повідомляє серверу, який формат відповіді очікує клієнт:
headers: {
"Accept": "application/json"
}Accept і Content-Type мають різне призначення:
Accept — формат очікуваної відповіді;
Content-Type — формат тіла поточного запиту.
HeadersЗаголовки можна створити за допомогою класу Headers:
const headers = new Headers();
headers.set("Accept", "application/json");
headers.set("Authorization", "Bearer token-123");
const response = await fetch("/api/profile", {
headers
});Методи Headers:
set(name, value) — встановити або замінити заголовок;
append(name, value) — додати значення;
get(name) — отримати значення;
has(name) — перевірити наявність;
delete(name) — видалити заголовок.
Тіло передається через властивість body. Воно потрібне переважно для POST, PUT і PATCH.
Об’єкт JavaScript потрібно перетворити на JSON-рядок за допомогою JSON.stringify():
const user = {
name: "Марія",
role: "admin"
};
const response = await fetch("/api/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify(user)
});fetch() не перетворює об’єкти на JSON автоматично. Якщо передати звичайний об’єкт напряму, запит не матиме очікуваного JSON-тіла.
Можна передати звичайний рядок:
await fetch("/api/messages", {
method: "POST",
headers: {
"Content-Type": "text/plain"
},
body: "Привіт із клієнта"
});URLSearchParamsДля даних у форматі URL-кодованої форми використовуйте URLSearchParams:
const formData = new URLSearchParams();
formData.set("username", "olena");
formData.set("language", "uk");
const response = await fetch("/api/settings", {
method: "POST",
body: formData
});У цьому випадку браузер встановить відповідний тип вмісту.
FormDataFormData зручно використовувати для HTML-форми та завантаження файлів:
const formData = new FormData();
formData.append("title", "Документ");
formData.append("description", "Навчальний файл");
const fileInput = document.querySelector("#file");
formData.append("file", fileInput.files[0]);
const response = await fetch("/api/documents", {
method: "POST",
body: formData
});Не встановлюйте Content-Type: multipart/form-data вручну. Браузер має додати boundary, який розділяє частини даних.
fetch() повертає проміс із об’єктом Response. Тіло відповіді читається окремим методом.
const response = await fetch("/api/users/42");
const user = await response.json();
console.log(user);Поширені методи читання тіла:
response.json() — JSON;
response.text() — текст;
response.blob() — двійкові дані, наприклад зображення;
response.arrayBuffer() — двійкові дані у вигляді ArrayBuffer;
response.formData() — дані форми.
Тіло відповіді можна прочитати лише один раз. Наприклад, після response.json() повторний виклик response.text() для тієї самої відповіді призведе до помилки.
Важлива особливість: fetch() не відхиляє проміс для статусів 4xx і 5xx.
Наприклад, відповідь зі статусом 404 усе одно буде успішно отримана на рівні мережі. Тому потрібно самостійно перевіряти response.ok або response.status.
async function loadUser(userId) {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) {
throw new Error(`Помилка HTTP: ${response.status}`);
}
return response.json();
}
loadUser(42)
.then((user) => {
console.log("Користувач:", user);
})
.catch((error) => {
console.error("Не вдалося завантажити користувача:", error.message);
});Властивість response.ok має значення true для статусів від 200 до 299.
Якщо сервер повертає помилку у форматі JSON, її можна прочитати окремо:
async function createUser(userData) {
const response = await fetch("/api/users", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(userData)
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.message || "Не вдалося створити користувача");
}
return result;
}Властивість credentials визначає, чи потрібно додавати до запиту cookies, HTTP-аутентифікацію та інші облікові дані.
Можливі значення:
"omit" — не надсилати облікові дані;
"same-origin" — надсилати їх для запитів до того самого джерела;
"include" — надсилати їх також у крос-доменних запитах.
Значення за замовчуванням — "same-origin".
const response = await fetch("https://api.example.com/profile", {
credentials: "include"
});Для крос-доменного запиту сервер також має дозволити credentials у CORS-відповіді. Самого параметра "include" на клієнті недостатньо.
Якщо автентифікація реалізована через bearer-токен, його зазвичай передають у заголовку:
const response = await fetch("/api/private-data", {
headers: {
Authorization: `Bearer ${token}`
}
});Властивість mode визначає, як браузер обробляє крос-доменний запит.
Основні значення:
"cors" — стандартний режим для дозволених крос-доменних запитів;
"same-origin" — дозволяє запити лише до того самого джерела;
"no-cors" — обмежений режим, у якому JavaScript не може прочитати більшість даних відповіді.
const response = await fetch("https://api.example.com/products", {
mode: "cors"
});CORS контролюється браузером і сервером. Клієнтський код не може самостійно «вимкнути» CORS.
Режим "no-cors" не є способом обійти CORS. У ньому відповідь зазвичай має тип opaque, а її статус і тіло недоступні для JavaScript.
Властивість cache керує використанням HTTP-кешу браузера.
Поширені значення:
"default" — стандартна поведінка кешу;
"no-store" — не використовувати кеш;
"reload" — звернутися до мережі та оновити кеш;
"no-cache" — перевірити актуальність кешованої відповіді;
"force-cache" — використати кешовану відповідь, якщо вона доступна.
const response = await fetch("/api/news", {
cache: "no-store"
});cache: "no-store" може бути корисним для даних, які не повинні повертатися з кешу, наприклад для поточного стану сесії.
Кешування також залежить від HTTP-заголовків, які надсилає сервер. Параметр cache не замінює правильну серверну політику кешування.
За замовчуванням браузер автоматично переходить за HTTP-перенаправленнями.
Властивість redirect має такі основні значення:
"follow" — автоматично переходити за перенаправленням;
"error" — вважати перенаправлення помилкою;
"manual" — передати обробку перенаправлення коду.
const response = await fetch("/old-page", {
redirect: "error"
});Значення "error" може бути корисним, коли програма не повинна непомітно переходити на іншу адресу.
Для скасування запиту використовується AbortController.
const controller = new AbortController();
const timeoutId = setTimeout(() => {
controller.abort();
}, 5000);
try {
const response = await fetch("/api/slow-data", {
signal: controller.signal
});
if (!response.ok) {
throw new Error(`HTTP-помилка: ${response.status}`);
}
const data = await response.json();
console.log(data);
} catch (error) {
if (error.name === "AbortError") {
console.log("Запит скасовано через тайм-аут");
} else {
console.error("Помилка запиту:", error);
}
} finally {
clearTimeout(timeoutId);
}Один сигнал можна передати кільком запитам, якщо їх потрібно скасувати одночасно:
const controller = new AbortController();
const requests = [
fetch("/api/profile", { signal: controller.signal }),
fetch("/api/notifications", { signal: controller.signal })
];
controller.abort();
await Promise.allSettled(requests);Нижче функція створює користувача, передає JSON, додає токен, обмежує час очікування і коректно обробляє помилки:
async function createUser(userData, token) {
const controller = new AbortController();
// Скасовуємо запит, якщо сервер не відповів за 10 секунд
const timeoutId = setTimeout(() => {
controller.abort();
}, 10_000);
try {
const response = await fetch("/api/users", {
method: "POST",
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
},
body: JSON.stringify(userData),
credentials: "same-origin",
cache: "no-store",
signal: controller.signal
});
const result = await response.json();
if (!response.ok) {
throw new Error(
result.message || `Сервер повернув статус ${response.status}`
);
}
return result;
} catch (error) {
if (error.name === "AbortError") {
throw new Error("Час очікування запиту вичерпано");
}
throw error;
} finally {
clearTimeout(timeoutId);
}
}
createUser(
{
name: "Ірина",
email: "iryna@example.com"
},
"token-123"
)
.then((user) => {
console.log("Створено користувача:", user);
})
.catch((error) => {
console.error("Помилка:", error.message);
});RequestКоли одна й та сама конфігурація запиту використовується кілька разів, її можна винести в об’єкт Request.
const request = new Request("/api/products", {
method: "GET",
headers: {
Accept: "application/json"
},
cache: "no-store"
});
const response = await fetch(request);
if (!response.ok) {
throw new Error(`HTTP-помилка: ${response.status}`);
}
const products = await response.json();
console.log(products);Request зберігає URL і параметри запиту. Його можна передати безпосередньо у fetch().
Неправильно:
fetch("/api/users", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: {
name: "Олена"
}
});Правильно:
fetch("/api/users", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
name: "Олена"
})
});404Неправильно покладатися лише на try...catch:
try {
const response = await fetch("/missing-resource");
console.log("Цей код може виконатися навіть для статусу 404");
} catch (error) {
console.error(error);
}Потрібно перевіряти response.ok:
const response = await fetch("/missing-resource");
if (!response.ok) {
throw new Error(`HTTP-помилка: ${response.status}`);
}Content-Type для FormDataНе встановлюйте вручну:
headers: {
"Content-Type": "multipart/form-data"
}Інакше може бути втрачений boundary, необхідний серверу для розбору даних. Передайте FormData у body, а заголовок залиште браузеру.
Неправильно:
const response = await fetch("/api/data");
const data = await response.json();
const text = await response.text();Тіло потрібно прочитати один раз. Якщо ті самі дані потрібні в різних форматах, заздалегідь оберіть відповідний метод або використайте response.clone() до читання тіла.
Не додавайте токени, паролі чи інші секрети до URL:
// Погано: токен потрапляє в історію браузера та журнали
fetch(`/api/data?token=${token}`);Для токенів автентифікації використовуйте захищений механізм, наприклад заголовок Authorization, з урахуванням вимог безпеки вашого застосунку.
Для типового JSON-запиту потрібно:
Вибрати HTTP-метод.
Додати Content-Type: application/json.
Перетворити тіло через JSON.stringify().
Перевірити response.ok.
Прочитати тіло відповіді відповідним методом.
Приклад мінімальної функції:
async function requestJson(url, options = {}) {
const response = await fetch(url, {
...options,
headers: {
Accept: "application/json",
...options.headers
}
});
if (!response.ok) {
throw new Error(`HTTP-помилка: ${response.status}`);
}
return response.json();
}fetch(url, options) дає змогу детально налаштувати HTTP-запит.
method визначає тип операції.
headers передає метадані, тип вмісту та дані автентифікації.
JSON у body потрібно серіалізувати через JSON.stringify().
Для FormData не слід вручну встановлювати Content-Type.
fetch() не вважає статуси 4xx і 5xx мережевою помилкою, тому перевіряйте response.ok.
credentials керує надсиланням cookies та інших облікових даних.
mode визначає поведінку крос-доменних запитів.
cache налаштовує використання кешу.
AbortController дає змогу скасувати запит або встановити тайм-аут.
Тіло відповіді читається окремо через json(), text(), blob() та інші методи.