Будьте в курсе последних событий, подпишитесь на обновления сайта

Основы объекта XMLHttpRequest

Основы объекта XMLHttpRequest

Здравствуйте!  Продолжаем  разбираться с AJAX  и в  этом уроке я разберу пожалуй  главный объект без которого трудно себе представить  технологию AJAX —  XMLHttpRequest (или, сокращенно  «XHR»)  он дает возможность из JavaScript делать HTTP-запросы к серверу без перезагрузки страницы, то есть это и есть AJAX.

Несмотря на,  то что в  название присутствует  слово «XML», XMLHttpRequest может работать в принципе  с любыми данными, а не только с XML.

объект xmlhttprequest

Использовать его очень просто. Давайте рассмотрим примеры.

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

Как правило, XMLHttpRequest используется для загрузки данных.

Для начала рассмотрим пример использования, который загружает файл с телефонами  phones.json из текущей директории и выдаёт его содержимое:

// 1. Создаём новый объект XMLHttpRequest var xhr1 = new XMLHttpRequest(); 
// 2. Конфигурируем его: GET-запрос на URL 'phones.json' xhr1.open('GET', 'phones.json', false); 
// 3. Отсылаем запрос xhr1.send(); // 4. Если код ответа сервера не 200, то это ошибка if (xhr1.status != 200) { 
// обработать ошибку alert( xhr1.status + ': ' + xhr1.statusText ); 
// пример вывода: 404: Not Found } 
else { // вывести результат alert( xhr1.responseText ); // responseText -- текст ответа. }

Далее мы более подробно разберём основные методы и свойства объекта XMLHttpRequest.

Установить соединение: open

Синтаксис:

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

Этот метод –  вызывается первым после создания объекта XMLHttpRequest.

Задаёт основные параметры запроса:

  • method – HTTP-метод. Используется GET либо POST.
  • URL – адрес запроса. Можно использовать не только http/https, но и другие протоколы, например ftp:// и file://.При этом есть ограничения безопасности, называемые «Same Origin Policy»: запрос со страницы можно отправлять только на тот же протокол://домен:порт, с которого она пришла.
  • async – если установлено в false, то запрос производится синхронно, если true – асинхронно.

«Синхронный запрос» означает, что после вызова xhr.send() и до ответа сервера поток будет «заморожен»: посетитель не сможет взаимодействовать со страницей – прокручивать, нажимать на кнопки и т.п. После получения ответа выполнение продолжится со следующей строки.

«Асинхронный запрос» означает, что браузер отправит запрос, а далее результат нужно будет получить через обработчики событий.

  • user, password – логин и пароль для HTTP-авторизации, если нужны.
Вызов open не открывает соединение

Заметим, что вызов open, в противоположность своему названию (open – англ. «открыть») не открывает соединение. Он лишь настраивает запрос, а открытие соединения  инициируется методом send.

Читайте также  XMLHttpRequest и кросс-доменные запросы

Отослать данные: send

Синтаксис:

xhr.send([body])

Именно этод метод открывает соединение и отправляет собственно запрос на сервер.

В body как раз  находится тело запроса. Не у всякого запроса есть тело, например у GET-запросов тела нет, а   вот у POST – основные данные как раз передаются через body.

Отмена: abort

Вызов xhr.abort() прерывает выполнение запроса. Если в  этом есть необходимость

Ответ: status, statusText, responseText

Основные свойства, содержащие ответ сервера:

status
HTTP-код ответа: 200, 404, 403. Может быть также равен 0, если сервер не ответил или при запросе на другой домен.
statusText
Текстовое описание статуса от сервера: OK, Not Found, Forbidden и так далее.
responseText
Текст ответа сервера.

Есть и ещё одно свойство, которое используется гораздо реже:

responseXML
Если сервер вернул XML, снабдив его правильным заголовком Content-type: text/xml, то браузер создаст из него XML-документ. П

Это свойство  используется редко, так как обычно используют не XML, а JSON. То есть, сервер возвращает JSON в виде текста, который браузер превращает в объект вызовом JSON.parse(xhr.responseText).

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

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

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

// Синхронный запрос xhr.open('GET', 'phones.json', false); 
// Отсылаем его xhr.send(); // ...весь JavaScript "подвиснет", пока запрос не завершится

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

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

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

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

Изменённый JS-код:

var xhr1 = new XMLHttpRequest(); 
xhr1.open('GET', 'phones.json', true); 
xhr1.send(); 
// (1) xhr1.onreadystatechange = function() { 
// (3) if (xhr1.readyState != 4) return; 
button.innerHTML = 'Готово!'; 
if (xhr1.status != 200) { 
alert(xhr1.status + ': ' + xhr1.statusText); 
} else { alert(xhr1.responseText); }
 } button.innerHTML = 'Загружаю...'; 
// (2) button.disabled = true;

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

Событие 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 повторяется при каждом получении очередного пакета данных по сети.

Точка разрыва пакетов не гарантирована

При состоянии readyState=3 (получен очередной пакет) мы можем посмотреть текущие данные в responseText и, казалось бы, могли бы работать с этими данными как с «ответом на текущий момент».

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

Чем это опасно? Хотя бы тем, что символы русского языка в кодировке UTF-8 кодируются двумя байтами каждый – и разрыв может возникнуть между ними.

Получится, что при очередном readyState в конце responseText будет байт-полсимвола, то есть он не будет корректной строкой – частью ответа! Если в скрипте как-то по-особому это не обработать, то неизбежны проблемы.

HTTP-заголовки

XMLHttpRequest умеет как указывать свои заголовки в запросе, так и читать присланные в ответ.

Для работы с HTTP-заголовками есть 3 метода:

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(name)

Вернет значение заголовка ответа name, кроме Set-Cookie и Set-Cookie2.

Например:

xhr.getResponseHeader('Content-Type')

getAllResponseHeaders()

Вернет все заголовки ответа, кроме Set-Cookie и Set-Cookie2.

Заголовки возвращаются в виде единой строки, например:

Cache-Control: max-age=31536000
Content-Length: 4260
Content-Type: image/png
Date: Sat, 08 Sep 2012 16:53:16 GMT
Между заголовками стоит перевод строки в два символа «\r\n» (не зависит от ОС), значение заголовка отделено двоеточием с пробелом «: «.  Этот формат задан стандартом.

Таким образом, если хочется получить объект с парами заголовок-значение, то эту строку необходимо разбить и обработать.

Таймаут

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

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

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

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

Все события

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

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

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

Итоги

Итак  вот типовой код для GET-запроса при помощи  объекта XMLHttpRequest:

var xhr = new XMLHttpRequest(); 
xhr.open('GET', '/my/server', true); 
xhr.send(); xhr.onreadystatechange = function() { 
if (this.readyState != 4) return; 
// по окончании запроса доступны: 
// status, statusText // responseText, 
responseXML (при content-type: text/xml) if (this.status != 200) { 
// обработать ошибку alert( 'ошибка: ' + (this.status ? this.statusText : 'запрос не удался') ); 
return; } // получить результат из this.responseText или this.responseXML }

Мы рассмотрели такие  методы XMLHttpRequest:

  • open(method, url, async, user, password)
  • send(body)
  • abort()
  • setRequestHeader(name, value)
  • getResponseHeader(name)
  • getAllResponseHeaders()

Свойства XMLHttpRequest:

  • timeout
  • responseText
  • responseXML
  • status
  • statusText

События:

  • onreadystatechange
  • ontimeout
  • onerror
  • onload
  • onprogress
  • onabort
  • onloadstart
  • onloadend

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Поделиться

Об авторе

admin administrator

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: