Fetch API
Современный способ HTTP-запросов в браузере и Node.js. Заменяет XMLHttpRequest.
Базовый запрос
fetch('/api/users')
.then((res) => res.json())
.then((data) => console.log(data));
fetch возвращает промис с объектом Response.
Response не бросает ошибку на 404
fetch отклоняет промис только при сетевой ошибке. HTTP 404 или 500 — это успешный промис:
const res = await fetch('/api/nonexistent');
res.ok; // false
res.status; // 404
Проверяй вручную:
async function request(url) {
const res = await fetch(url);
if (!res.ok) {
throw new Error(`HTTP ${res.status}`);
}
return res.json();
}
Методы
fetch('/api/users', { method: 'POST' });
fetch('/api/users/1', { method: 'PUT' });
fetch('/api/users/1', { method: 'PATCH' });
fetch('/api/users/1', { method: 'DELETE' });
Тело запроса
JSON:
fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Алиса' }),
});
FormData:
const data = new FormData(form);
fetch('/api/upload', { method: 'POST', body: data });
Не устанавливай Content-Type для FormData — браузер сам поставит с boundary.
Заголовки
fetch('/api/users', {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Bearer ${token}`,
},
});
Чтение ответа
const res = await fetch('/api/data');
await res.json(); // JSON
await res.text(); // текст
await res.blob(); // бинарные данные
await res.arrayBuffer();
await res.formData();
Можно прочитать тело только один раз.
Query-параметры
const params = new URLSearchParams({ page: 1, sort: 'date' });
fetch(`/api/users?${params}`);
AbortController
Отмена запроса:
const controller = new AbortController();
fetch('/api/data', { signal: controller.signal })
.then((res) => res.json())
.catch((err) => {
if (err.name === 'AbortError') {
console.log('отменено');
}
});
// отменить
controller.abort();
Таймаут
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
try {
const res = await fetch('/api/data', { signal: controller.signal });
return await res.json();
} finally {
clearTimeout(timeout);
}
Обёртка
const API_URL = import.meta.env.VITE_API_URL;
async function request(path, options = {}) {
const res = await fetch(`${API_URL}${path}`, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
...options.headers,
},
...options,
});
if (!res.ok) {
const error = await res.json().catch(() => ({}));
throw new Error(error.message ?? `HTTP ${res.status}`);
}
if (res.status === 204) return null;
return res.json();
}
const users = await request('/api/users');
CORS
При запросе с другого домена сервер должен вернуть заголовки:
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type
Если их нет — браузер блокирует ответ.
Credentials
Куки и авторизация:
fetch('/api/user', { credentials: 'include' });
same-origin— только свой домен (по умолчанию)include— всегдаomit— никогда
Кеш
fetch('/api/data', { cache: 'no-store' });
fetch('/api/data', { cache: 'force-cache' });
fetch('/api/data', { cache: 'reload' });
Итоги
fetch— промис-based HTTP- Не отклоняется на 404 — проверяй
res.ok - Методы через
options.method - JSON:
JSON.stringify+Content-Type - AbortController для отмены
- Обёртка для единообразия