Полный цикл в digital

Объект XMLHttpRequest

Код javascript может взаимодействовать с каким-нибудь ресурсом в сети интернет, например с сервером. Для взаимодействия кода javascript с сервером обычно применяется такая технология как Ajax. Ajax представляет технологию для отправки запросов к серверу из клиентского кода JavaScript без перезагрузки страницы. Сам термин расшифровывается как Asynchronous JavaScript And XML. То есть изначально AJAX предполагал асинхронное взаимодействие клиента и сервера посредством данных в формате XML. Хотя сейчас XML во многом вытеснил формат JSON, в любом случае AJAX революционизировал веб-среду, позволив создавать динамичные отзывчивые веб-приложения.

Для создания приложений использующих Ajax, применяются различные способы. Но самым распространенным способом является использование объекта XMLHttpRequest:

let xhr = new XMLHttpRequest();

После создания объекта XMLHttpRequest можно отправлять запросы к серверу, для начала надо вызвать метод open() для инициализации:

xhr.open(method, url, async, user, password)

Эта функция принимает пять параметров, из которых первые два являются обязательными:

  1. method тип запроса GET, POST, PUT, DELETE и т.д.
  2. url адрес ресурса, к которому отправляется запрос
  3. async логическое значение которое указывает будет ли запрос асинхронным. Если значение true (значение по умолчанию), то запрос асинхронный. Синхронный и асинхронный режим отличаются тем, что запрос в синхронном режиме пока запрос не выполнится, остальной код javascript не может выполняться. Если запрос отправляется в асинхронном режиме, то параллельно с выполнением запроса можно выполнять также и другой код javascript. И в большинстве случаев, как правило, используется именно асинхронный режим
  4. user имя пользователя которое применяется при его аутентификации на сервере (то есть для определения, какой именно пользователь осуществил запрос), по умолчанию равно null
  5. password пароль пользователя, который применяется при его аутентификации на сервере, по умолчанию равно null

Например, запрос типа GET на файл исполнитель xmlhttprequest.php:

xhr.open("GET", "xmlhttprequest.php");

После инициализации запроса методом open() можно отправить запрос с помощью метода send(). В body находится тело запроса. Не у всякого запроса есть тело, например у GET тела нет, у POST основные данные как раз передаются через body:

xhr.send(body)

Вызов метода abort() прерывает выполнение запроса:

xhr.abort()

Ответы XMLHttpRequest

Объект XMLHttpRequest имеет ряд свойств, которые позволяют проконтролировать выполнение запроса:

  1. status содержит статусный код ответа HTTP, который пришел от сервера. С помощью статусного кода можно судить об успешности запроса или об ошибках, которые могли бы возникнуть при его выполнении. Например, статусный код 200 указывает на то, что запрос прошел успешно. Код 403 говорит о необходимости авторизации для выполнения запроса, а код 404 сообщает, что ресурс не найден и так далее
  2. statusText Текстовое описание статуса от сервера OK, Not Found, Forbidden и так далее
  3. responseType возвращает тип ответа, есть следующие типы:
    "" пустая строка
    arraybuffer ответ представляет объект ArrayBuffer, которые содержит бинарные данные
    blob ответ представляет объект Blob, которые содержит бинарные данные
    document ответ представляет документ HTML/XML
    json ответ представляет данные в формате json
    text ответ представляет текст
  4. response возвращает ответ сервера
  5. responseText возвращает ответа сервера в виде текста
  6. responseXML возвращает XML/HTML, если ответ от сервера в формате XML/HTML

Синхронные и асинхронные запросы

Если в методе open установить параметр async равным false, то запрос будет синхронным.

Синхронные вызовы используются чрезвычайно редко, так как блокируют взаимодействие со страницей до окончания загрузки. Посетитель не может даже прокручивать её. Никакой JavaScript не может быть выполнен, пока синхронный вызов не завершён – в общем, в точности те же ограничения как alert.

Если синхронный вызов занял слишком много времени, то браузер предложит закрыть «зависшую» страницу.

Из-за такой блокировки получается, что нельзя отослать два запроса одновременно. Кроме того, забегая вперёд, заметим, что ряд продвинутых возможностей, таких как возможность делать запросы на другой домен и указывать таймаут, в синхронном режиме не работают.

Из всего вышесказанного уже должно быть понятно, что синхронные запросы используются чрезвычайно редко, а асинхронные – почти всегда.

Для того, чтобы запрос стал асинхронным, укажем параметр async равным true.

let xhr = new XMLHttpRequest();
xhr.open("GET", "xmlhttprequest.php", true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState != 4) return;
if (xhr.status != 200) {
// обработать ошибку
alert(xhr.status + ": " + xhr.statusText);
} else {
// вывести результат
alert(xhr.responseText);
}
};

Если в open указан третий аргумент true (или если третьего аргумента нет), то запрос выполняется асинхронно. Это означает, что после вызова xhr.send() код не «зависает», а преспокойно продолжает выполняться, а результат приходит через событие xhr.onreadystatechange.

Событие readystatechange

Событие readystatechange происходит несколько раз в процессе отсылки и получения ответа. При этом можно посмотреть «текущее состояние запроса» в свойстве xhr.readyState.

В примере выше мы использовали только состояние 4 (запрос завершён), но есть и другие.

Все состояния, по спецификации:

const unsigned short UNSENT = 0;  // начальное состояние
const unsigned short OPENED = 1;  // вызван open
const unsigned short HEADERS_RECEIVED = 2;  // получены заголовки
const unsigned short LOADING = 3;  // загружается тело (получен очередной пакет данных)
const unsigned short DONE = 4;  // запрос завершён

Запрос проходит их в порядке 0 -> 1 -> 2 -> 3 -> … -> 3 -> 4, состояние 3 повторяется при каждом получении очередного пакета данных по сети.

HTTP-заголовки

XMLHttpRequest умеет как указывать свои заголовки в запросе, так и читать присланные в ответ. Для работы с HTTP-заголовками есть 3 метода:

setRequestHeader

setRequestHeader(name, value), устанавливает заголовок name запроса со значением value:

xhr.setRequestHeader('Content-Type', 'application/json');

Нельзя установить заголовки, которые контролирует браузер, например Referer или Host и ряд других (полный список тут).

Особенностью XMLHttpRequest является то, что отменить setRequestHeader невозможно. Повторные вызовы лишь добавляют информацию к заголовку, например:

xhr.setRequestHeader('X-Auth', '123');
xhr.setRequestHeader('X-Auth', '456');
// в результате будет заголовок:
// X-Auth: 123, 456

getResponseHeader

getResponseHeader(name), возвращает значение заголовка ответа name, кроме Set-Cookie и Set-Cookie2:

xhr.getResponseHeader('Content-Type');

getAllResponseHeaders

getAllResponseHeaders(), возвращает все заголовки ответа, кроме Set-Cookie и Set-Cookie2. Заголовки возвращаются в виде единой строки. Между заголовками стоит перевод строки в два символа "\r\n" (не зависит от ОС), значение заголовка отделено двоеточием с пробелом ": ". Этот формат задан стандартом. Таким образом, если хочется получить объект с парами заголовок-значение, то эту строку необходимо разбить и обработать:

Cache-Control: max-age=31536000
Content-Length: 4260
Content-Type: image/png
Date: Sat, 08 Sep 2012 16:53:16 GMT

Таймаут

Максимальную продолжительность асинхронного запроса можно задать свойством timeout:

xhr.timeout = 30000;  // 30 секунд (в миллисекундах)

При превышении этого времени запрос будет оборван и сгенерировано событие ontimeout:

xhr.ontimeout = function() {
alert( 'Извините, запрос превысил максимальное время' );
}

Полный список событий

Современная спецификация предусматривает следующие события по ходу обработки запроса:

  • loadstart запрос начат
  • progress браузер получил очередной пакет данных, можно прочитать текущие полученные данные в responseText
  • abort запрос был отменён вызовом xhr.abort()
  • error произошла ошибка
  • load запрос был успешно (без ошибок) завершён
  • timeout запрос был прекращён по таймауту
  • loadend запрос был завершён (успешно или неуспешно)

Используя эти события можно более удобно отслеживать загрузку (onload) и ошибку (onerror), а также количество загруженных данных (onprogress).

Ранее мы видели ещё одно событие – readystatechange. Оно появилось гораздо раньше, ещё до появления текущего стандарта.

Пример использования асинхронно

function loadPhones() {
let xhr = new XMLHttpRequest();
xhr.open("GET", "xmlhttprequest.php", true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState != 4) return;
if (xhr.status != 200) {
// обработать ошибку
alert(xhr.status + ": " + xhr.statusText);
} else {
// вывести результат
alert(xhr.responseText);
}
};
}

Пример использования синхронно

function loadPhones() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'xmlhttprequest.php', false);
xhr.send();
if (xhr.status != 200) {
// обработать ошибку
alert('Ошибка ' + xhr.status + ': ' + xhr.statusText);
} else {
// вывести результат
alert(xhr.responseText);
}
}
Заполните форму уже сегодня!
Для начала сотрудничества необходимо заполнить заявку или заказать обратный звонок. В ответ получите коммерческое предложение, которое будет содержать индивидуальную стратегию с учетом требований и поставленных задач
Работаем по будням с 9:00 до 18:00. Заявки, отправленные в выходные, обрабатываем в первый рабочий день до 12:00.
Спасибо, ваш запрос принят и будет обработан!
Эйч Маркетинг