Объект XMLHttpRequest

Для реализации обмена данными между Web-браузером и сервером используется объект XMLHttpRequest. Этот объект в фоновом режиме может отправить запрос и получить результат, который не отображается в окне Web-браузера. Получить доступ к результату запроса можно с помощью языка JavaScript.

Прежде чем использовать объект XMLHttpRequest, необходимо его создать с помощью оператора new. Проблема заключается в том, что в разных Web-браузерах объект создается по-разному. В современных Web-браузерах используется встроенный объект window.XMLHttpRequest, а в устаревшем Internet Explorer — ActiveX-объект MSXML2.XMLHTTP или Microsoft.XMLHTTP. Кроссбраузерный код создания объекта приведен в листинге 3.4.

Листинг 3.4. Создание объекта XMLHttpRequest

var req = null;
if (window.XMLHttpRequest) {
   req = new XMLHttpRequest();
}
else {
   if (window.ActiveXObject) { // IE
      var XMLHTTP = ['MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.3.0',
                     'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'];
      for (var i = 0; i < XMLHTTP.length; i++) {
         try { // Обработка исключений
            req = new ActiveXObject(XMLHTTP[i]);
            break; // Если объект создан, то выход из цикла
         }
         catch (e) {}
      }
   }
}
if ( req ) {
   window.alert('Объект успешно создан');
}
else {
   window.alert('Ваш Web-браузер не поддерживает технологию AJAX');
}

Для сокращения объема книги в дальнейших примерах мы будем упрощать код создания объекта XMLHttpRequest до одной инструкции:

var req = new XMLHttpRequest();

Методы

Объект XMLHttpRequest содержит следующие методы:

  • open(<Метод передачи данных>, <URL-адрес>[, <Тип запроса>]) — подготавливает запрос к отправке на сервер. В первом параметре можно указать значения "GET", "POST" или др. Параметр <URL-адрес> предназначен для указания URL-адреса скрипта, которому будет отправлен запрос (в виде строки или объекта URL). Можно указать как абсолютный путь, так и относительный. При указании абсолютного пути следует иметь в виду, что запрос может быть отправлен только к домену, с которого был загружен текущий документ. Кроме того, некоторые Web-браузеры не позволяют отправить запрос к домену http://www.site.ru/, если документ был загружен с http://site.ru/. По этой причине лучше указывать относительный путь от корня сайта или от местонахождения текущего документа. Если для отправки данных используется метод GET, то после названия скрипта указываются передаваемые параметры. В параметре <Тип запроса> могут быть заданы следующие значения:
  • true — асинхронный запрос (выполнение текущего скрипта не приостанавливается до получения ответа; значение по умолчанию);
  • false — синхронный запрос (выполнение текущего скрипта будет продолжено только после получения ответа сервера).

В большинстве случаев используются именно асинхронные запросы, т. к. ответ от сервера может занять некоторое время. Метод open() имеет еще два необязательных параметра: имя пользователя и пароль. На практике эти параметры применяются очень редко, и мы их рассматривать не будем;

  • setRequestHeader(<Заголовок>, <Значение>) — позволяет добавить заголовок запроса. В большинстве случаев используется для указания типа передаваемых данных методом POST:
req.setRequestHeader('Content-Type', 
                     'application/x-www-form-urlencoded');
  • overrideMimeType(<MIME-тип>) — позволяет указать MIME-тип ответа, если сервер его не передал или передал неправильно. Метод поддерживается не всеми Web-браузерами, поэтому лучше перед использованием проверить его наличие:
if (req.overrideMimeType) {
   req.overrideMimeType('text/xml');
}
  • getAllResponseHeaders() — возвращает строку со всеми заголовками ответа сервера (кроме заголовка Set-Cookie) или пустую строку в случае ошибки:
if (req.readyState == 4) {
   console.log( req.getAllResponseHeaders() );
}

Заголовки разделяются двумя символами: \r\n. Название заголовка от его значения отделяется двоеточием и пробелом:

Date: Thu, 14 May 2020 14:20:57 GMT
Expires: Tue, 12 May 2020 01:00:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 24
Content-Type: text/html; charset=utf-8
  • getResponseHeader(<Заголовок>) — возвращает значение указанного заголовка ответа сервера или значение null, если заголовок не найден или в случае ошибки:
if (req.readyState == 4) {
   console.log( req.getResponseHeader('Content-Type') );
   // text/html; charset=utf-8
}
  • send(<Данные для отправки методом POST>) — отправляет запрос на сервер. В качестве параметра при запросе методом GET указывается значение null:
req.send(null);

Для метода POST указывается строка передаваемых данных. Передаваемые данные должны быть закодированы с помощью функции encodeURIComponent():

var formData = 'txt1=' + encodeURIComponent('Текст');
req.send(formData);
  • abort() — отменяет текущий запрос.

Свойства

Свойства объекта XMLHttpRequest:

  • onreadystatechange — в этом свойстве указывается ссылка на функцию-обработчик при асинхронных запросах:
req.onreadystatechange = processReqChange;

Обратите внимание на тот факт, что название функции указывается без круглых скобок и параметров. Если указать круглые скобки, то смысл происходящего будет другим. Функция будет выполнена, и результат ее работы будет присвоен свойству onreadystatechange. Так как в функцию-обработчик невозможно передать параметр, то внутри функции мы можем обратиться к объекту XMLHttpRequest, только если он будет объявлен в глобальной области видимости. Это не всегда удобно. Однако передать параметр можно, указав в качестве обработчика анонимную функцию, внутри которой происходит вызов функции с параметром:

req.onreadystatechange = function() {
   processReqChange(req);
};

Этим способом мы и будем пользоваться в дальнейших примерах. Функция processReqChange() будет вызываться несколько раз при каждом изменении статуса обработки запроса;

  • readyState — содержит текущий статус обработки запроса. Может принимать следующие значения:
  • 0 — UNSENT — объект запроса создан оператором new;
  • 1 — OPENED — запрос подготовлен с помощью метода open();
  • 2 — HEADERS_RECEIVED — запрос отправлен методом send() и получены заголовки ответа сервера;
  • 3 — LOADING — ответ доступен, но загружен не полностью;
  • 4 — DONE — ответ полностью загружен с сервера и доступен для обработки или что-то пошло не так.

В дальнейшем нас будет интересовать именно статус 4;

  • status — содержит код возврата при значении свойства readyState, равном 4. Успешными считаются коды в пределах от 200 до 299;
  • statusText — содержит статус возврата в виде строки, например, "OK" для кода 200;
  • timeout — позволяет задать максимальное время ожидания ответа сервера в миллисекундах:
req.timeout = 5000; // 5 секунд
  • ontimeout — указывается ссылка на функцию, которая будет вызвана, если истекло время ожидания, заданное с помощью свойства timeout:
req.ontimeout = function() {
   document.getElementById('div_ajax').innerHTML = 
      'Истекло время ожидания';
};
  • onabort — указывается ссылка на функцию, которая будет вызвана, если запрос был отменен с помощью метода abort():
req.onabort = function() {
   document.getElementById('div_ajax').innerHTML = 
      'Вызван метод abort()';
};
  • onerror — указывается ссылка на функцию, которая будет вызвана, если запрос не может быть выполнен, например, отсутствует соединение с Интернетом:
req.onerror = function() {
   window.alert('Ошибка');
};
  • onloadstart — указывается ссылка на функцию, которая будет вызвана в начале выполнения запроса:
req.onloadstart = function() {
   document.getElementById('div_ajax').innerHTML = 'Загрузка...';
};
  • onloadend — указывается ссылка на функцию, которая будет вызвана в конце выполнения запроса вне зависимости от успешности выполнения;
  • onload — указывается ссылка на функцию, которая будет вызвана в конце загрузки при получении ответа сервера, включая ответы сервера при ошибках, например, при ошибке 404 (страница не найдена):
req.onload = function() {
   if (req.status == 200) { // Запрос успешно обработан
      console.log(req.responseText);
   }
   else {
      console.log('Статус: ' + req.status);
   }
};
  • onprogress — указывается ссылка на функцию, которая будет периодически вызываться в процессе загрузки. Внутри функции через объект события доступны следующие свойства:
  • lengthComputable — содержит значение true, если сервер отправил заголовок Content-Length;
  • loaded — количество загруженных байтов;
  • total — общее количество байтов (если сервер отправил заголовок Content-Length).

Пример:

req.onprogress = function(e) {
   console.log('lengthComputable : ' + e.lengthComputable);
   console.log('Загружено : ' + e.loaded + ' из ' + e.total);
};
  • upload — содержит ссылку на объект, который позволяет обработать события передачи данных на сервер методом POST, например, события загрузки на сервер большого файла. Назначить обработчики событий можно с помощью свойств onloadstart, onprogress, onabort, onerror, onload, ontimeout и onloadend. Пример:
req.upload.onprogress = function(e) {
   console.log('Отправлено : ' + e.loaded + ' из ' + e.total);
};
req.upload.onloadend = function() {
   console.log('Отправка данных завершена');
};
  • withCredentials — по умолчанию другому домену не отправляются cookies и заголовки HTTP-авторизации. Чтобы это изменить, нужно присвоить этому свойству значение true:
req.withCredentials = true;

Получить доступ к ответу сервера можно с помощью следующих свойств:

  • responseText — ответ в виде текста, фрагмента HTML-документа или объекта JSON;
  • responseXML — ответ в виде XML-документа или значение null. Свойство будет доступно, только если в заголовках ответа сервера указан заголовок:
Content-Type: application/xml

или:

Content-Type: text/xml

Кроме того, XML-документ должен быть иметь правильную структуру и соответствовать спецификации DOM.

В последних версиях Web-браузеров вместо свойств responseText и responseXML можно использовать свойство response, но предварительно нужно указать ожидаемый тип ответа сервера с помощью свойства responseType:

  • "" (значение по умолчанию) или "text" — ответ в виде текста;
  • "document" — ответ в виде HTML или XML;
  • "json" — ответ в формате JSON (ответ автоматически преобразуется из строки в объект JSON);
  • "arraybuffer" — бинарные данные в виде объекта ArrayBuffer;
  • "blob" — бинарные данные в виде объекта Blob.

При ошибке свойство response может вернуть значение null. Пример получения текста:

req.responseType = 'text';
req.onload = function() {
  if (req.status == 200) { // Запрос успешно обработан
    var serverData = req.response;
    console.log(serverData);
  }
};

Итак, как вы уже знаете, ответ сервера может быть предоставлен в виде:

  • фрагмента HTML-документа, скрипта JavaScript или просто текста;
  • XML-документа;
  • объекта JSON.

Рассмотрим варианты обмена данными более подробно.

Учебник по jQuery и AJAX
Учебник по jQuery и AJAX в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов