XMLHttpRequest: обзор (устаревший)

XMLHttpRequest (XHR) — браузерный API для асинхронных HTTP-запросов, предшественник Fetch API, основа AJAX-эпохи (2005–2015).

Зачем нужно

XHR встречается в легаси-коде и старых библиотеках (jQuery $.ajax, Axios в старых версиях). Понимание XHR необходимо для чтения и поддержки кода, написанного до 2015 года, а также для понимания эволюции браузерных API. Для нового кода используйте Fetch API.

Где используется

  • Легаси-код, написанный до 2015–2017 годов
  • Старые версии jQuery, Axios (теперь использует fetch/http)
  • Прогресс загрузки файлов — XHR.onprogress (fetch не поддерживает нативно)
  • IE11 и очень старые браузеры (fetch там недоступен)

XHR vs Fetch

Критерий XMLHttpRequest Fetch
API callback-based Promise-based
Прогресс xhr.onprogress нет нативно
Отмена xhr.abort() AbortController
CORS поддерживается поддерживается
Читаемость низкая высокая
IE11 да нет (нужен polyfill)

Базовый пример XHR

// GET-запрос
const xhr = new XMLHttpRequest();

xhr.open('GET', '/api/users');
xhr.setRequestHeader('Authorization', `Bearer ${token}`);

xhr.onload = function {
  if (xhr.status === 200) {
    const users = JSON.parse(xhr.responseText);
    console.log(users);
  } else {
    console.error('Ошибка:', xhr.status, xhr.statusText);
  }
};

xhr.onerror = function {
  console.error('Сетевая ошибка');
};

xhr.send;
// POST-запрос с JSON
const xhr = new XMLHttpRequest();
xhr.open('POST', '/api/users');
xhr.setRequestHeader('Content-Type', 'application/json');

xhr.onload = () => {
  if (xhr.status === 201) {
    const created = JSON.parse(xhr.responseText);
    console.log('Создан:', created.id);
  }
};

xhr.send(JSON.stringify({ name: 'Антон', email: 'anton@example.com' }));

Прогресс загрузки (уникальная возможность XHR)

const xhr = new XMLHttpRequest();
xhr.open('POST', '/api/upload');

// Прогресс отправки файла
xhr.upload.onprogress = (event) => {
  if (event.lengthComputable) {
    const percent = (event.loaded / event.total * 100).toFixed(1);
    progressBar.style.width = percent + '%';
    console.log(`Загружено: ${percent}%`);
  }
};

xhr.onload = () => console.log('Загрузка завершена:', xhr.status);

const formData = new FormData();
formData.append('file', fileInput.files[0]);
xhr.send(formData);

Эквивалент на Fetch (современный код)

// XHR выше переписывается на Fetch так:
const res = await fetch('/api/users', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Антон', email: 'anton@example.com' }),
});

if (!res.ok) throw new Error(`HTTP ${res.status}`);
const created = await res.json();
console.log('Создан:', created.id);

Частые ошибки

  • Использование XHR в новом коде — есть Fetch API, значительно удобнее
  • Забывают вызвать xhr.send — запрос не отправляется
  • Проверяют xhr.status в xhr.onerror — там status всегда 0 (сетевая ошибка)
  • Не устанавливают Content-Type при отправке JSON — сервер не знает формат

Связанные темы

Ресурсы