Fetch: headers, mode, credentials
Параметры headers, mode и credentials в Fetch API управляют заголовками запроса, политикой CORS и передачей куки/токенов.
Зачем нужно
Дефолтный fetch(url) работает для простых GET-запросов на тот же домен. Как только появляется авторизация, кросс-доменные запросы или нестандартные заголовки — нужно явно указывать эти параметры. Непонимание credentials приводит к тому, что куки и сессии не передаются; неверный mode ломает CORS-запросы.
Где используется
- Авторизованные запросы к API (JWT, session cookies)
- Кросс-доменные запросы (CORS) к сторонним API
- Preflight-запросы с нестандартными заголовками
- Загрузка ресурсов с другого домена (изображения, шрифты)
headers
// Объект заголовков — самый простой способ
const res = await fetch('/api/data', {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer eyJhbG...',
'X-Request-Id': crypto.randomUUID,
},
});
// Headers API — позволяет проверять и добавлять заголовки
const headers = new Headers();
headers.set('Authorization', `Bearer ${token}`);
headers.append('Accept-Language', 'ru');
const res2 = await fetch('/api/profile', { headers });
// Чтение заголовков ответа
console.log(res.headers.get('Content-Type')); // application/json
console.log(res.headers.get('X-Total-Count')); // 156
mode
// 'cors' (по умолчанию) — запрос с CORS-проверкой
// Работает, если сервер вернул Access-Control-Allow-Origin
const res = await fetch('https://api.example.com/data', { mode: 'cors' });
// 'same-origin' — запрос только на тот же домен; выбросит ошибку иначе
const res2 = await fetch('/api/internal', { mode: 'same-origin' });
// 'no-cors' — запрос без CORS-заголовков, ответ «непрозрачный» (opaque)
// Тело недоступно — используется только для отправки «пинга»
await fetch('https://analytics.example.com/ping', {
mode: 'no-cors',
method: 'POST',
body: JSON.stringify({ event: 'pageview' }),
});
credentials
// 'omit' — никогда не отправлять куки
const res = await fetch('https://api.example.com/data', { credentials: 'omit' });
// 'same-origin' — куки только для одного домена (по умолчанию)
const res2 = await fetch('/api/profile', { credentials: 'same-origin' });
// 'include' — всегда отправлять куки, в т.ч. кросс-доменные
// Требует: Access-Control-Allow-Credentials: true
// Access-Control-Allow-Origin: <точный origin> (не '*')
const res3 = await fetch('https://api.example.com/profile', {
credentials: 'include',
});
Паттерн авторизованного API-клиента
const api = {
baseUrl: 'https://api.example.com',
async request(path, options = {}) {
const token = localStorage.getItem('token');
const res = await fetch(`${this.baseUrl}${path}`, {
mode: 'cors',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
...(token && { Authorization: `Bearer ${token}` }),
...options.headers,
},
...options,
});
if (res.status === 401) { window.location.href = '/login'; return; }
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
},
get: (path, opts) => api.request(path, { ...opts, method: 'GET' }),
post: (path, body, opts) =>
api.request(path, { ...opts, method: 'POST', body: JSON.stringify(body) }),
};
Частые ошибки
- Не указывают
credentials: 'include'— куки сессии не передаются в кросс-доменных запросах - Не устанавливают
Content-Type: application/jsonпри отправке JSON - Ожидают прочитать тело
no-cors-ответа — он всегда opaque - Сочетают
Access-Control-Allow-Origin: *сcredentials: 'include'— браузер запрещает эту комбинацию
Связанные темы
- _MOC Сеть
- Протокол HTTP -- основы
- Content-Type -- типы данных
- Abort Controller -- отмена запросов
- Cookie -- безопасные атрибуты (HttpOnly, Secure, SameSite)