Синхронные и асинхронные запросы
Содержание:
- Событие onprogress в деталях
- Использование XMLHTTPRequest
- Object reference[edit | edit source]
- Bypassing the cache
- Using FormData objects
- Основы
- Ограничения безопасности. Кросс-доменный XMLHttpRequest
- Summary
- Основы AJAX
- Using XMLHttpRequest from JavaScript modules / XPCOM components
- GET и POST-запросы. Кодировка.
- Создание асинхронных запросов с помощью XHR
- JSON Example
- §Brief History of XHR
Событие onprogress в деталях
При обработке события есть ряд важных тонкостей.
Можно, конечно, их игнорировать, но лучше бы знать.
Заметим, что событие, возникающее при , имеет одинаковый вид на стадии отправки (в обработчике ) и при получении ответа (в обработчике ).
Оно представляет собой объект типа со свойствами:
-
Сколько байт уже переслано.
Имеется в виду только тело запроса, заголовки не учитываются.
-
Если , то известно полное количество байт для пересылки, и оно хранится в свойстве .
-
Общее количество байт для пересылки, если известно.
А может ли оно быть неизвестно?
- При отправке на сервер браузер всегда знает полный размер пересылаемых данных, так что всегда содержит конкретное количество байт, а значение всегда будет .
- При скачивании данных – обычно сервер в начале сообщает их общее количество в HTTP-заголовке . Но он может и не делать этого, например если сам не знает, сколько данных будет или если генерирует их динамически. Тогда будет равно . А чтобы отличить нулевой размер данных от неизвестного – как раз служит , которое в данном случае равно .
Ещё особенности, которые необходимо учитывать при использовании :
Событие происходит при каждом полученном/отправленном байте, но не чаще чем раз в 50 мс.
Это обозначено в .
В процессе получения данных, ещё до их полной передачи, доступен , но он не обязательно содержит корректную строку.
Можно до окончания запроса заглянуть в него и прочитать текущие полученные данные
Важно, что при пересылке строки в кодировке UTF-8 кириллические символы, как, впрочем, и многие другие, кодируются 2 байтами. Возможно, что в конце одного пакета данных окажется первая половинка символа, а в начале следующего – вторая
Поэтому полагаться на то, что до окончания запроса в находится корректная строка нельзя. Она может быть обрезана посередине символа.
Исключение – заведомо однобайтные символы, например цифры или латиница.
Сработавшее событие не гарантирует, что данные дошли.
Событие срабатывает, когда данные отправлены браузером. Но оно не гарантирует, что сервер получил, обработал и записал данные на диск. Он говорит лишь о самом факте отправки.
Поэтому прогресс-индикатор, получаемый при его помощи, носит приблизительный и оптимистичный характер.
Использование XMLHTTPRequest
Различают два использования XmlHttpRequest. Первое — самое простое, синхронное.
Синхронный XMLHttpRequest
В этом примере через XMLHTTPRequest с сервера запрашивается страница http://example.org/, и текст ответа сервера показывается через alert().
var xmlhttp = getXmlHttp() xmlhttp.open('GET', '/xhr/test.html', false); xmlhttp.send(null); if(xmlhttp.status == 200) { alert(xmlhttp.responseText); }
Здесь сначала создается запрос, задается открытие () синхронного соединение с адресом /xhr/test.html и запрос отсылается с null,
т.е без данных.
При синхронном запросе браузер «подвисает» и ждет на строчке 3, пока сервер не ответит на запрос. Когда ответ получен — выполняется строка 4, код ответа сравнивается с 200 (ОК), и при помощи alert
печатается текст ответа сервера. Все максимально просто.
Свойство responseText получит такой же текст страницы, как браузер, если бы Вы в перешли на /xhr/test.html. Для сервера
GET-запрос через XmlHttpRequest ничем не отличается от обычного перехода на страницу.
Асинхронный XMLHttpRequest
Этот пример делает то же самое, но асинхронно, т.е браузер не ждет выполнения запроса для продолжения скрипта. Вместо этого к свойству onreadystatechange подвешивается
функция, которую запрос вызовет сам, когда получит ответ с сервера.
var xmlhttp = getXmlHttp() xmlhttp.open('GET', '/xhr/test.html', true); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) { if(xmlhttp.status == 200) { alert(xmlhttp.responseText); } } }; xmlhttp.send(null);
Асинхронность включается третьим параметром функции open. В отличие от синхронного запроса, функция send() не останавливает
выполнение скрипта, а просто отправляет запрос.
Запрос xmlhttp регулярно отчитывается о своем состоянии через вызов функции xmlhttp.onreadystatechange. Состояние под номером 4 означает конец выполнения, поэтому функция-обработчик
при каждом вызове проверяет — не настало ли это состояние.
Вообще, список состояний readyState такой:
- 0 — Unitialized
- 1 —
- 2 — Loaded
- 3 — Interactive
- 4 — Complete
Состояния 0-2 вообще не используются.
Вызов функции с состоянием Interactive в теории должен происходить каждый раз при получении очередной порции данных от сервера.
Это могло бы быть удобным для обработки ответа по частям, но Internet Explorer не дает доступа к уже полученной части ответа.
Firefox дает такой доступ, но для обработки запроса по частям состояние Interactive все равно неудобно из-за сложностей обнаружения ошибок соединения.
Поэтому Interactive тоже не используется.
На практике используется только последнее, Complete.
Если хотите углубиться в тонкости багов браузеров c readyState, отличными от 4, то многие из них рассмотрены в статье на.
Не используйте синхронные запросы
Синхронные запросы применяются только в крайнем случае, когда кровь из носу необходимо дождаться ответа сервера до продолжения скрипта. В 999 случаях из 1000
можно использовать асинхронные запросы. При этом общий алгоритм такой:
- Делаем асинхронный запрос
- Рисуем анимированную картинку или просто запись типа «Loading…»
- В onreadystatechange при достижении состояния 4 убираем Loading и, в зависимости от status вызываем обработку ответа или ошибки.
Кроме того, иногда полезно ставить ограничение на время запроса. Например, хочется генерировать ошибку, если запрос висит более 10 секунд.
Для этого сразу после send() через setTimeout ставится вызов обработчика ошибки, который очищается при получении ответа и обрывает запрос с генерацией ошибки,
если истекли 10 секунд.
Таймаут на синхронный запрос ставить нельзя, браузер может висеть долго-долго.. А вот на асинхронный — пожалуйста.
Этот пример демонстрирует такой таймаут.
var xmlhttp = getXmlHttp() xmlhttp.open("POST", "/someurl", true); xmlhttp.onreadystatechange=function(){ if (xmlhttp.readyState != 4) return clearTimeout(timeout) // очистить таймаут при наступлении readyState 4 if (xmlhttp.status == 200) { // Все ок ... alert(xmlhttp.responseText); ... } else { handleError(xmlhttp.statusText) // вызвать обработчик ошибки с текстом ответа } } xmlhttp.send("a=5&b=4"); // Таймаут 10 секунд var timeout = setTimeout( function(){ xmlhttp.abort(); handleError("Time over") }, 10000); function handleError(message) { // обработчик ошибки ... alert("Ошибка: "+message) ... }
Object reference[edit | edit source]
Methodsedit | edit source
- abort()
- Cancels the current request.
- getAllResponseHeaders()
- Returns the complete set of HTTP headers as a string.
- getResponseHeader(headerName)
- Returns the value of the specified HTTP header.
- open(method, URL)
- open(method, URL, async)
- open(method, URL, async, userName)
- open(method, URL, async, userName, password)
-
Specifies the method, URL, and other optional attributes of a request.
- The method parameter can have a value of GET, POST, HEAD, PUT, DELETE, or a variety of other HTTP methods listed in the W3C specification.
- The URL parameter may be either a relative or complete URL.
- The async parameter specifies whether the request should be handled asynchronously or not – true means that script processing carries on after the send() method, without waiting for a response, and false means that the script waits for a response before continuing script processing.
- send(content)
- Sends the request. content can be a string or reference to a document.
- setRequestHeader(label, value)
- Adds a label/value pair to the HTTP header to be sent.
Propertiesedit | edit source
- onreadystatechange
- Specifies a reference to an event handler for an event that fires at every state change
- readyState
-
Returns the state of the object as follows:
- 0 = uninitialized – open() has not yet been called.
- 1 = open – send() has not yet been called.
- 2 = sent – send() has been called, headers and status are available.
- 3 = receiving – Downloading, responseText holds partial data
- 4 = loaded – Finished.
- responseText
- Returns the response as a string.
- responseXML
- Returns the response as XML. This property returns an XML document object, which can be examined and parsed using W3C DOM node tree methods and properties.
- responseBody
-
Returns the response as a binary encoded string. This property is not part of the native XMLHttpRequest wrapper. For this property to be available, the XHR object must be created with an ActiveX component. A JScript example:
if (typeof ActiveXObject !== "undefined") { xmlhttp = new ActiveXObject("MSXML2.XMLHTTP"); xmlhttp.open("GET", "#", false); xmlhttp.send(null); alert(xmlhttp.responseBody); } else { alert("This browser does not support Microsoft ActiveXObjects.") }
- status
- statusText
- Returns the status as a string (e.g. «Not Found» or «OK»).
Bypassing the cache
Normally, tries to retrieve content from the cache, if it’s available. To bypass this, do the following:
var req = new XMLHttpRequest(); req.open('GET', url, false); req.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE; req.send(null);
Note: This approach will only work in Gecko-based software, as the attribute is Gecko-specific.
An alternate, cross-browser compatible approach is to append a timestamp to the URL, being sure to include a «?» or «&» as appropriate. For example:
http://foo.com/bar.html
becomes
http://foo.com/bar.html?12345
and
http://foo.com/bar.html?foobar=baz
becomes
http://foo.com/bar.html?foobar=baz&12345
Since the local cache is indexed by URL, this causes every request to be unique, thereby bypassing the cache.
You can automatically adjust URLs using the following code:
var req = new XMLHttpRequest(); req.open("GET", url += (url.match(/\?/) == null ? "?" : "&") + (new Date()).getTime(), false); req.send(null);
Using FormData objects
The object lets you compile a set of key/value pairs to send using . It’s primarily intended for use in sending form data, but can be used independently from forms in order to transmit keyed data. The transmitted data is in the same format that the form’s method would use to send the data if the form’s encoding type were set to «multipart/form-data».
You can build a object yourself, instantiating it then appending fields to it by calling its method, like this:
This example builds a object containing values for fields named «username» and «accountnum», then uses the method to send the form’s data.
To construct a object that contains the data from an existing , specify that form element when creating the object:
newFormData = new FormData(someFormElement);
For example:
You can also add data to the object between retrieving it from a form and sending it, like this:
This lets you augment the form’s data before sending it along, to include additional information that’s not necessarily user editable on the form.
You can also send files using . Simply include an element of type «file»:
Then you can send it using code like the following:
Note that this example is directing the output to a Perl CGI script running on the server, and handles HTTP errors, although not prettily.
Основы
XMLHttpRequest имеет два режима работы: синхронный и асинхронный.
Сначала рассмотрим асинхронный, так как в большинстве случаев используется именно он.
Чтобы сделать запрос, нам нужно выполнить три шага:
-
Создать .
-
Инициализировать его.
Этот метод обычно вызывается сразу после . В него передаются основные параметры запроса:
- – HTTP-метод. Обычно это или .
- – URL, куда отправляется запрос: строка, может быть и объект URL.
- – если указать , тогда запрос будет выполнен синхронно, это мы рассмотрим чуть позже.
- , – логин и пароль для базовой HTTP-авторизации (если требуется).
Заметим, что вызов , вопреки своему названию, не открывает соединение. Он лишь конфигурирует запрос, но непосредственно отсылается запрос только лишь после вызова .
-
Послать запрос.
Этот метод устанавливает соединение и отсылает запрос к серверу. Необязательный параметр содержит тело запроса.
Некоторые типы запросов, такие как , не имеют тела. А некоторые, как, например, , используют , чтобы отправлять данные на сервер. Мы позже увидим примеры.
-
Слушать события на , чтобы получить ответ.
Три наиболее используемых события:
- – происходит, когда получен какой-либо ответ, включая ответы с HTTP-ошибкой, например 404.
- – когда запрос не может быть выполнен, например, нет соединения или невалидный URL.
- – происходит периодически во время загрузки ответа, сообщает о прогрессе.
Вот полный пример. Код ниже загружает с сервера и сообщает о прогрессе:
После ответа сервера мы можем получить результат запроса в следующих свойствах :
- Код состояния HTTP (число): , , и так далее, может быть в случае, если ошибка не связана с HTTP.
- Сообщение о состоянии ответа HTTP (строка): обычно для , для , для , и так далее.
- (в старом коде может встречаться как )
- Тело ответа сервера.
Мы можем также указать таймаут – промежуток времени, который мы готовы ждать ответ:
Если запрос не успевает выполниться в установленное время, то он прерывается, и происходит событие .
URL с параметрами
Чтобы добавить к URL параметры, вида , и корректно закодировать их, можно использовать объект URL:
Ограничения безопасности. Кросс-доменный XMLHttpRequest
Для ограничения XmlHttpRequest используется философия «Same Origin Policy». Она очень проста — каждый сайт в своей песочнице. Запрос можно делать только на адреса
с тем же протоколом, доменом, портом, что и текущая страница.
Т.е, со страницы на адресе http://site.com нельзя сделать XmlHttpRequest на адрес https://site.com, http://site.com:81 или http://othersite.com
Это создает проблему, если хочется взять контент с другого сайта. Как правило, в этом случае вместо XmlHttpRequest используются другие средства, например, загрузка через
динамически создаваемый тег
Проксирование
Самый простой способ обойти это ограничение — проксирование. Допустим, мы хотим сделать запрос с http://site.com на http://remote.com/get.html.
Чтобы обойти ограничение, вместо указания remote.com в методе open(), там ставится специальный URL вида http://site.com/proxy/remote.com/get.html. Так что запрос приходит на наш веб-сервер, который проксирует его на сервер site.com, который в свою очередь обрабатывает этот запрос, как нужно.
Если remote.com находится на другом сервере, то серверу site.com придется проксировать посетителю как запрос, так и ответ. При этом, разумеется, никак не будут задействованы куки remote.com, так что не получится отдельной авторизации, учета пользователей или чтото в этом роде с отдельными куками.
Проксирование настраивается соответствующим модулем (mod_proxy, proxy module и т.п.) веб-сервера для всех адресов, начинающихся на /proxy.
Например, при использовании web-сервера Apache, для проксирования нужны директивы ProxyPass, ProxyPassReverse. Кроме того, доступны еще модули, которые по необходимости правят урлы, разархивируют контент
Использование наддомена
Часто кроссбраузерные запросы — это
- Способ обойти ограничения в 2 одновременных соединения к одному домену-порту.
- Способ использовать два разных сервера в общении с посетителем. Например, на chat.site.ru — чат-демон, на www.site.ru — веб-сервер.
Кросс-доменные запросы с поддомена типа http://a.site.com, http://b.site.com на базовый домен site.com допустимы при использовании свойства document.domain, которое надо установить в site.com
// на странице a.site.com ... document.domain='site.com' ... // все, теперь могу делать XmlHttpRequest на site.com xmlhttp.open(..'http://site.com/feedme.php'..)
Запрос на старый домен
В браузере Internet Explorer, чтобы сделать запрос на старый домен a.site.com, нужно вернуть свойство document.domain обратно. В остальных браузерах это приводит к ошибке, поэтому можно оформить код типа такого:
var oldDomain = document.domain document.domain = "site.com" try { // для IE, в остальных браузерах ошибка... document.domain = oldDomain; } catch(e) { /* ... но в них все и так работает */ } //... работаем с a.site.com ...
Same origin и фреймы
Приятным бонусом свойства document.domain является возможность коммуникации между фреймами/ифреймами на одном домене.
То есть, например, если
- во фрейме с адреса http://a.site.com установлен document.domain=’site.com’,
- на фрейме с адреса http://b.site.com установлен домен document.domain=’site.com’
- на фрейме с адреса http://site.com установлен (обязательно!) домен document.domain=’site.com’
То эти три фрейма могут свободно общаться посредством javascript и XmlHttpRequest.
Обычно такая коммуникация используется при создании чатов/событий с сервера, когда на site.com находится основной веб-сервер, а на chat.site.com висит чат-демон.
Internet Explorer trusted zone
Любые запросы допустимы между сайтами, находящимися в доверенной (trusted) зоне Internet Explorer. Так что, внутренний корпоративный портал может быть у всех пользователей в этой зоне, и он сможет делать запросы к любым сайтам.
XhrIframeProxy
Еще один хитрый подход называется , и позволяет делать XmlHttpRequest к любым доменам при помощи хитрого iframe-хака. Он основан на том, что фреймы с разных доменов могут читать и менять друг у друга anchor, т.е часть адреса после решетки ‘#’. За счет этого организуется специальный протокол, по которому «проксируется» XmlHttpRequest.
Этот метод, в принципе, вполне жизнеспособен, особенно для небольшого объема данных.
Кросс-доменные запросы в FF3/IE8/Opera9..
В спецификации HTML 5 предусмотрены кросс-доменные запросы .
Создатели Firefox и Opera реализовали этот вариант, см. например MDC: .
Разработчики IE8 пошли другим путем и предлагают .
Оба способа вполне жизнеспособны и уже пригодны для использования в интранет-приложениях, когда на всех машинах администратор ставит одинаковый браузер, например, Firefox 3 ?
Summary
Typical code of the GET-request with :
There are actually more events, the lists them (in the lifecycle order):
- – the request has started.
- – a data packet of the response has arrived, the whole response body at the moment is in .
- – the request was canceled by the call .
- – connection error has occurred, e.g. wrong domain name. Doesn’t happen for HTTP-errors like 404.
- – the request has finished successfully.
- – the request was canceled due to timeout (only happens if it was set).
- – triggers after , , or .
The , , , and events are mutually exclusive. Only one of them may happen.
The most used events are load completion (), load failure (), or we can use a single handler and check the properties of the request object to see what happened.
We’ve already seen another event: . Historically, it appeared long ago, before the specification settled. Nowadays, there’s no need to use it, we can replace it with newer events, but it can often be found in older scripts.
If we need to track uploading specifically, then we should listen to same events on object.
Основы AJAX
Знакомство с технологией AJAX начнём с рассмотрения примера (для начинающих), который будет запрашивать информацию с сервера посредством синхронного запроса.
Синхронный запрос в отличие от асинхронного, после его отправки и до получения ответа, замораживает веб-страницу, т.е. делает её недоступной для пользователя. Синхронные запросы на сайтах используются довольно редко, но изучать технологию AJAX начинающим лучше именно с них.
Перед тем как перейти к созданию примера, рассмотрим основные этапы, сопровождающие разработку фрагмента страницы, работающей в соответствии с технологией AJAX. При этом все действия в основном осуществляются в коде JavaScript после наступления какого-либо события на странице (пользователь нажал кнопку и т.п.) и состоят из следующих этапов:
- Получение некоторой информации (данных) со страницы или формы (при необходимости)
- Отправление запрос на веб-сервер
- Получение ответа с веб-сервера
- Отображение результатов на странице, если ответ был успешен.
Using XMLHttpRequest from JavaScript modules / XPCOM components
Instantiating from a JavaScript module or an XPCOM component works a little differently; it can’t be instantiated using the constructor. The constructor is not defined inside components and the code results in an error. You’ll need to create and use it using a different syntax.
Instead of this:
var req = new XMLHttpRequest(); req.onprogress = onProgress; req.onload = onLoad; req.onerror = onError; req.open("GET", url, true); req.send(null);
Do this:
var req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"] .createInstance(Components.interfaces.nsIXMLHttpRequest); req.onprogress = onProgress; req.onload = onLoad; req.onerror = onError; req.open("GET", url, true); req.send(null);
For C++ code you would need to the component to an in order to add event listeners, but chances are in C++ using a channel directly would be better.
GET и POST-запросы. Кодировка.
Во время обычного submit’а формы браузер сам кодирует значения полей и составляет тело GET/POST-запроса для посылки на сервер. При работе через XmlHttpRequest, это нужно делать самим, в javascript-коде. Большинство проблем и вопросов здесь связано с непониманием, где и какое кодирование нужно осуществлять.
Вначале рассмотрим общее кодирование запросов, ниже — правильную работу с русским языком для windows-1251.
Существуют два вида кодирования HTTP-запроса. Основной — urlencoded, он же — стандартное кодирование URL. Пробел представляется как %20, русские буквы и большинство спецсимволов кодируются, английские буквы и дефис оставляются как есть.
Способ, которым следует кодировать данные формы при submit’е, задается в ее HTML-таге:
<form method="get"> // метод GET с кодировкой по умолчанию <form method="post" enctype="application/x-www-form-urlencoded"> // enctype явно задает кодировку <form method="post"> // метод POST с кодировкой по умолчанию (urlencoded, как и предыдущая форма)
Если форма submit’ится обычным образом, то браузер сам кодирует (urlencode) название и значение каждого поля данных ( и т.п.) и отсылает форму на сервер в закодированном виде.
Формируя XmlHttpRequest, мы должны формировать запрос «руками», кодируя поля функцией .
Конечно, пропускать через encodeURIComponent стоит только те переменные, в которых могут быть спецсимволы или не английские буквы, т.е которые и будут как раз закодированы.
Например, для посылки GET-запроса с произвольными параметрами name и surname, их необходимо закодировать вот так:
// Пример с GET ... var params = 'name=' + encodeURIComponent(name) + '&surname=' + encodeURIComponent(surname) xmlhttp.open("GET", '/script.html?'+params, true) ... xmlhttp.send(null)
В методе POST параметры передаются не в URL, а в теле, посылаемом через . Поэтому нужно указывать не в адресе, а при вызове
Кроме того, при POST обязателен заголовок Content-Type, содержащий кодировку. Это указание для сервера — как обрабатывать (раскодировать) пришедший запрос.
// Пример с POST ... var params = 'name=' + encodeURIComponent(name) + '&surname=' + encodeURIComponent(surname) xmlhttp.open("POST", '/script.html', true) xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') ... xmlhttp.send(params)
Заголовки Content-Length, Connection в POST-запросах, хотя их и содержат некоторые «руководства», обычно не нужны. Используйте их, только если Вы действительно знаете, что делаете.
Запросы multipart/form-data
Второй способ кодирования — это отсутствие кодирования. Например, кодировать не нужно для пересылки файлов. Он указывается в форме (только для POST) так:
<form method="post" enctype="multipart/form-data">
В этом случае при отправке данных на сервер ничего не кодируется. А сервер, со своей стороны, посмотрев на Content-Type(=multipart/form-data), поймет, что пришло.
Возможности XmlHttpRequest позволяют создать запрос с любым телом. Например, можно вручную сделать POST-запрос, загружающий на сервер файл. Функционал создания
таких запросов есть, в частности, во фреймворке . Но можно реализовать его и самому, прочитав о нужном формате тела POST и заголовках.
Кодировка (языковая)
Если Вы используете только UTF-8 — пропустите эту секцию.
Все идущие на сервер параметры GET/POST, кроме случая multipart/form-data, кодируются в UTF-8. Не в кодировке страницы, а именно в UTF-8. Поэтому, например, в PHP их нужно при необходимости перекодировать функцией iconv.
<?php // ajax.php $name = iconv('UTF8','CP1251',$_GET); ?>
С другой стороны, ответ с сервера браузер воспринимает именно в той кодировке, которая указана в заголовке ответа Content-Type. Т.е, опять же, в PHP, чтобы браузер воспринял ответ в windows-1251 и нормально отобразил данные на странице в windows-1251,
нужно послать заголовок с кодировкой в php-коде, например так:
<?php // ajax.php header('Content-Type: text/plain; charset=utf-8'); ?>
Или же, такой заголовок должен добавить сервер. Например, в apache автоматически добавляется кодировка опцией:
# в конфиге апача AddDefaultCharset windows-1251
Создание асинхронных запросов с помощью XHR
Что такое асинхронный запрос, мы уже разобрали выше. Т.е. это такой, который выполняется в фоне и не мешает пользователю взаимодействовать со страницей.
А это значит, что при отправке такого запроса, страница не «замораживается», с ней можно работать дальше.
– это аббревиатура от объекта , позволяющего взаимодействовать с сервером.
1. Начинается написания запроса с создания экземпляра объекта :
const xhr = new XMLHttpRequest();
2. После этого следует инициализировать запрос с помощью метода :
xhr.open(method, url]]);
Где:
- – метод отправки запроса на сервер (, , , , );
- – URL для отправки запроса;
- – определяет, как следует выполнять запрос: асинхронно ( – по умолчанию) или нет ();
- и – имя пользователя и пароль, использующиеся для аутентификации (по умолчанию имеют значение ).
Например:
// GET – метод, по которому будем делать запрос // requestURL – переменная, содержащая URL для отправки запроса xhr.open('GET', requestURL);
3. Следующий шаг – это назначить обработчик на событие объекта :
xhr.onreadystatechange = function() { // ... }
Это событие происходит при изменении статуса запроса .
– это свойство, содержащее числовой код, по которому можно определить в какой сейчас стадии находится запрос.
Статусы кодов :
- 0 – создан объект , но метод ещё не вызывался;
- 1 – открыто новое соединение с помощью (этот этап также включает установку значений HTTP заголовкам с помощью );
- 2 – отправлен (вызван и получены заголовки ответа);
- 3 – получена часть ответа;
- 4 – завершён.
Из всех этих статусов нам интересен только 4. Он будет означать, что ответ от сервера получен и его можно обработать. Остальные коды на практике практически не используются.
Таким образом напишем проверку на равенство значения числу 4:
xhr.onreadystatechange = function() { if (xhr.readyState !== 4) { return; } // все в порядке, ответ получен }
Следующее, что нужно проверить – это статус HTTP-ответа. Он находится в свойстве .
Если запрос был успешно выполнен сервером, то его статус будет 200. Другие ответы нам в большинстве случаев не интересны. Например, если равен 404 (запрашиваемый URL не найден), то в этом случае запрашиваемых данных нет и мы можем только как-то обработать это ошибку.
Добавим ещё одно условие в код: проверку на равенство 200.
xhr.onreadystatechange = function() { if (xhr.readyState !== 4 && xhr.status !== 200) { return; } // все в порядке, ответ получен и его статус равен 200 }
Теперь, если всё в порядке, мы можем получить данные и делать с ними всё, то угодно.
Получить данные (ответ от сервера) можно в виде строки () или объекта XML Document ().
Например, выведем полученный ответ от севера в консоль:
xhr.onreadystatechange = function() { if (xhr.readyState !== 4 || xhr.status !== 200) { return; } const response = xhr.responseText; console.log(response); }
4. Последний этап – это отправка запроса. Выполняется это с помощью метода .
Если запрос асинхронный, то выполнение не останавливает дальнейшее выполнение программы. В противном случае (если запрос синхронный), программа приостанавливается и возобновляет своё выполнение только после получения ответа от сервера.
В при необходимости можно передать аргумент (данные серверу в теле запроса). Если это не сделать, то по умолчанию будет использоваться значение .
Запросы GET создаются без тела, все параметры, которые нужно передать серверу здесь указывается в самом URL. Поэтому чтобы тело запроса было пустое, как уже было отмечено выше, нужно вызвать метод без аргументов или с аргументом .
Отправим запрос:
xhr.send();
Итоговый код:
const xhr = new XMLHttpRequest(); xhr.open('GET', requestURL); xhr.onreadystatechange = function() { if (xhr.readyState !== 4 || xhr.status !== 200) { return; } const response = xhr.responseText; console.log(response); } xhr.send();
JSON Example
This example reads a menu from myTutorials.txt, and displays the menu in a web
page:
JSON Example
<div id=»id01″></div><script>var xmlhttp = new XMLHttpRequest();
var url = «myTutorials.txt»;xmlhttp.onreadystatechange = function()
{ if (this.readyState == 4 && this.status ==
200) { var myArr = JSON.parse(this.responseText);
myFunction(myArr); }};xmlhttp.open(«GET», url, true);
xmlhttp.send();function myFunction(arr) { var
out = «»; var i; for(i = 0; i <
arr.length; i++) { out += ‘<a
href=»‘ + arr.url + ‘»>’ +
arr.display + ‘</a><br>’; }
document.getElementById(«id01»).innerHTML = out;}
</script>
§Brief History of XHR
Despite its name, XHR was never intended to be tied to XML
specifically. The XML prefix is a vestige of a decision to ship the first
version of what became known as XHR as part of the MSXML library in
Internet Explorer 5:
Mozilla modeled its own implementation of XHR against Microsoft’s and
exposed it via the XMLHttpRequest interface. Safari, Opera, and other
browsers followed, and XHR became a de facto standard in all major
browsers—hence the name and why it stuck. In fact, the official W3C
Working Draft specification for XHR was only published in 2006, well
after XHR came into widespread use!
However, despite its popularity and key role in the AJAX revolution,
the early versions of XHR provided limited capabilities: text-based-only
data transfers, restricted support for handling uploads, and inability to
handle cross-domain requests. To address these shortcomings, the
«XMLHttpRequest Level 2» draft was published in 2008, which added a
number of new features:
-
Support for request timeouts
-
Support for binary and text-based data transfers
-
Support for application override of media type and encoding of
responses -
Support for monitoring progress events of each request
-
Support for efficient file uploads
-
Support for safe cross-origin requests
In 2011, «XMLHttpRequest Level 2» specification was merged with the
original XMLHttpRequest working draft. Hence, while you will often find
references to XHR version or level 1 and 2, these distinctions are no
longer relevant; today, there is only one, unified XHR specification. In
fact, all the new XHR2 features and capabilities are offered via the same
XMLHttpRequest API: same interface, more features.