Взаимодействие с сервером, основа современной веб-разработки․ Будь то загрузка данных пользователя, отправка формы или получение обновлений в реальном времени, браузер предоставляет мощные инструменты для сетевого обмена․ На стандартом де-факто является Fetch API, однако понимание предшественника — XMLHttpRequest (XHR), необходимо для работы с легаси-кодом и глубокого понимания процессов․
Содержание
- Современный стандарт: Fetch API
- Выполнение GET-запросов
- Отправка данных: POST, PUT, DELETE
- Продвинутые настройки (объект
init) - Легаси: XMLHttpRequest (XHR)
- Сравнение Fetch и XHR
- Распространенные ошибки и их решение
- Отладка через DevTools
Современный стандарт: Fetch API
Fetch API — это интерфейс нового поколения для выполнения сетевых запросов․ В отличие от XMLHttpRequest, он построен на Промисах (Promises), что позволяет писать чистый, линейный код с использованием async/await или цепочек ․then․
По данным MDN Web Docs, Fetch-запросы контролируются директивой connect-src политики безопасности содержимого (Content Security Policy), что дает более гранулярный контроль над безопасностью по сравнению со старыми подходами․
Базовый синтаксис
fetch(url, options)
․then(response => { /* обработка ответа / })
․catch(error => { / обработка сетевых ошибок */ }); - url — строка с адресом ресурса (может быть объектом
Request)․ - options (необязательно) — объект конфигурации (
init), описывающий метод, заголовки, тело запроса и др․
Выполнение GET-запросов
GET-запросы используются для получения данных․ По умолчанию fetch использует именно метод GET․
Пример с async/await (рекомендуемый стиль)
async function getUserData(userId) {
try {
const url = `https://api․example․com/users/${userId}`;
const response = await fetch(url);
// Важно: fetch не выбрасывает ошибку при HTTP-статусах 4xx/5xx
if (!response․ok) {
throw new Error(`Ошибка HTTP: ${response․status}`);
}
const data = await response․json; // Парсинг JSON
console․log('Данные получены:', data);
return data;
} catch (error) {
console․error('Сетевая ошибка или ошибка парсинга:', error);
}
}
getUserData(123); Пример с ․then
fetch('https://api․vk․com/method/users․get?user_id=210700286&v=5․52')
․then(response => response․json)
․then(data => alert(data․response[0]․first_name))
․catch(err => console․error('Ошибка:', err)); Отправка данных: POST, PUT, DELETE
Для изменения данных на сервере используются методы POST, PUT, PATCH, DELETE․ Тело запроса передается в свойстве body объекта опций․
Пример отправки JSON (POST)
async function postData(url, data) {
// Default options are marked with *
const response = await fetch(url, {
method: 'POST', // GET, POST, PUT, DELETE, etc․
mode: 'cors', // no-cors, cors, same-origin
cache: 'no-cache', // default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, same-origin, omit
headers: {
'Content-Type': 'application/json',
// 'Authorization': 'Bearer *' // Токены маскируем
},
redirect: 'follow', // manual, follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: JSON․stringify(data) // Тело запроса должно быть строкой
});
return response․json; // Парсим ответ сервера
}
// Использование
postData('https://api․example․com/items', { name: 'Новый товар', price: 100 })
․then(data => console․log('Создано:', data)); Отправка формы (FormData)
const form = document․getElementById('myForm');
form;addEventListener('submit', async (e) => {
e․preventDefault;
const formData = new FormData(form);
// FormData автоматически устанавливает заголовок Content-Type: multipart/form-data
const response = await fetch('/submit-form', {
method: 'POST',
body: formData
});
const result = await response․json;
alert(result․message);
}); Продвинутые настройки (объект init)
Второй параметр fetch, это объект init, позволяющий тонко настроить запрос․ Основные свойства:
| Свойство | Описание | Значения по умолчанию |
|---|---|---|
method | HTTP-метод | 'GET' |
headers | Объект Headers или обычный объект | {} |
body | Тело запроса (строка, FormData, Blob, URLSearchParams) | null |
mode | Режим CORS | 'cors' |
credentials | Политика куков/авторизации | 'same-origin' |
cache | Режим кэширования | 'default' |
redirect | Обработка редиректов | 'follow' |
signal | AbortSignal для отмены запроса | — |
Отмена запроса (AbortController)
const controller = new AbortController;
const signal = controller․signal;
fetch('/long-process', { signal })
․catch(err => {
if (err․name === 'AbortError') console․log('Запрос отменен');
else console․error(err);
});
// Отмена через 5 секунд
setTimeout( => controller․abort, 5000); Легаси: XMLHttpRequest (XHR)
XMLHttpRequest — это старый API, все еще поддерживаемый во всех браузерах для совместимости․ По словам Никиты с WebbDEV (Medium), это «XMLHttpRequest нового поколения» (в контексте Fetch), но XHR остается в кодовых базах, написанных до 2015-2017 годов․
Базовый пример (Асинхронный)
const xhr = new XMLHttpRequest;
// 1․ Настройка: метод, URL, асинхронность (true)
xhr․open('GET', 'https://api․example․com/data', true);
// 2․ Установка заголовков (опционально)
xhr․setRequestHeader('Content-Type', 'application/json');
xhr․setRequestHeader('Authorization', 'Bearer *'); // Маскировка токена
// 3․ Обработчики событий
xhr․onload = function {
if (xhr․status >= 200 && xhr․status < 300) {
const data = JSON․parse(xhr․responseText);
console․log('Успех:', data);
} else {
console․error('Ошибка сервера:', xhr․status, xhr․responseText);
}
};
xhr․onerror = function {
console․error('Сетевая ошибка');
};
xhr․onprogress = function(event) {
if (event․lengthComputable) {
console․log(`Загружено ${event․loaded} из ${event․total}`);
}
};
// 4․ Отправка
xhr․send; // Для GET body обычно null или опущен POST запрос на сервлет (пример из Stack Overflow)
var xhr = new XMLHttpRequest;
// Обратите внимание: протокол (http://) обязателен
xhr․open('POST', 'http://localhost:8080/MyLay/Message', true);
xhr․setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// В теле передаем строку ключ=значение
xhr․send('param1=value1¶m2=value2'); Важно: В примерах из интернета (например, 2016 год) часто встречается ошибка, отсутствие протокола в URL (
localhost:8080․․․вместоhttp://localhost:8080․․․), что приводит к ошибке синтаксиса или некорректному определению хоста․
Сравнение Fetch и XHR
| Характеристика | Fetch API | XMLHttpRequest |
|---|---|---|
| Парадигма | Промисы (Promise-based) | Колбэки / События (Event-based) |
| Читаемость | Высокая (async/await) | Низкая (Callback Hell) |
| Streaming | Поддерживает ReadableStream (response․body) | Ограниченно (responseType='stream' не везде) |
| Отмена | AbortController (стандарт) | xhr․abort (устарело) |
| Прогресс загрузки | Только чтение потока (сложнее) | Событие onprogress (просто) |
| Куки (Credentials) | Не отправляются по умолчанию (кроме same-origin) | Отправляются автоматически |
| Ошибки HTTP (404, 500) | Не выбрасывают исключение (проверка response․ok) | Не выбрасывают (проверка xhr․status) |
| Поддержка браузеров | Все современные (IE требует полифилл) | Все, включая IE6+ |
Распространенные ошибки и их решение
CORS (Cross-Origin Resource Sharing)
Симптом: Access to fetch at '․․․' from origin '․․․' has been blocked by CORS policy․
Причина: Браузер блокирует запрос к другому домену/порту/протоколу, если сервер не вернул заголовок Access-Control-Allow-Origin․
Решение: Настраиваеться на сервере (Backend: Nginx, Apache, Spring Boot, Node․js, Python)․ Клиентский JS это не исправит (кроме проксирования)․
Ошибка 405 Method Not Allowed
Контекст: Частая проблема на Stack Overflow при работе с Spring Boot / Servlets․
Причина: Эндпоинт на сервере не поддерживает этот HTTP-метод (например, контроллер ожидает @GetMapping, а приходит POST)․
Проверка: Откройте вкладку Network в DevTools -> выберите запрос -> вкладка Headers -> проверьте Request Method и сопоставьте с аннотацией контроллера (@PostMapping, @GetMapping)․
fetch не ловит 404/500 в catch
Особенность: fetch считает выполненным любой ответ от сервера (даже 500)․ Ошибка в catch попадает только при сетевом сбое (нет интернета, DNS ошибка, CORS блокировка)․
Паттерн: Всегда проверяйте response․ok или response․status․
const response = await fetch(url);
if (!response․ok) {
// Ручной бросок ошибки для перехода в catch
const errorData = await response․json․catch( => ({}));
throw new Error(`Server error: ${response․status}`, { cause: errorData });
} Проблема чтения тела ошибки в XHR
Как отмечено в вопросах на Stack Overflow, XMLHttpRequest не позволяет прочитать responseText / response при ошибке, если не настроен правильный responseType или если сервер не вернул заголовки CORS для ошибки․ Fetch в этом плане надежнее — response․json читается при любом статусе․
Отладка через Инструменты разработчика (DevTools)
Главный инструмент диагностики — вкладка Network (Сеть)․
- Откройте DevTools (F12 или Ctrl+Shift+I)․
- Перейдите на вкладку Network․
- Поставьте галочку Preserve log (Сохранять лог), чтобы не терять запросы при перезагрузке․
- Выполните действие на сайте․
- Кликните по нужному запросу в списке․
Что анализировать:
- Headers (Заголовки): Request URL, Request Method, Status Code, Response Headers (CORS, Content-Type, Set-Cookie), Request Headers (Authorization, Cookie, User-Agent)․
- Payload (Полезная нагрузка): То, что ушло в
body(JSON, Form Data, Query String Parameters)․ - Timing (Время): Разбивка по этапам: DNS Lookup, TCP Connection, TLS, Request Sent, Waiting (TTFB), Content Download․ Помогает найти узкое место (медленный бэкенд или сеть)․
- Initiator (Инициатор): Какая строка JS-кода инициировала запрос (стек вызовов)․
На 2026 год отправка запросов через браузер — это в 99% случаев работа с Fetch API и async/await․ Понимание механики HTTP (методы, заголовки, коды состояния, CORS, кэширование) важнее знания синтаксиса конкретной функции․
Чек-лист перед коммитом:
- Обработаны ли ошибки сети (
try/catch) и ошибки HTTP (response․ok)? - Установлен ли правильный
Content-Typeдля тела запроса? - Нужны ли куки/авторизация (
credentials: 'include')? - Есть ли защита от утечек токенов в логах (маскировка в консоли)?
- Проверено ли поведение в DevTools (вкладка Network)?
Удачной разработки! Если остались вопросы по конкретным кейсам (WebSockets, Server-Sent Events, GraphQL, gRPC-web), изучайте соответствующие спецификации, но база всегда одна: HTTP + Fetch․