Javascript метод xmlhttprequest.setrequestheader()

Частые проблемы¶

Кеширование

Многие браузеры поддерживают кеширование ответов на XmlHttpRequest запросы. При этом реализации кеширования немного разные.

Например, при повторном XmlHttpRequest на тот же URL, Firefox посылает запрос с заголовком «» со значением, указанным в заголовке «» предыдущего ответа.

А Internet Explorer делает так, только когда кешированный ответ устарел, т. е. после времени из заголовка «Expires» предыдущего ответа. Поэтому, кстати, многие думают, что Internet Explorer вообще не очищает кеш ответов.

Самое простое решение проблемы — просто убрать кеширование. Например, при помощи заголовков, или добавлением случайного параметра в URL типа:

Есть, однако, ряд случаев, когда кеширование XMLHttpRequest браузером полезно, улучшает время ответа и экономит трафик.

Пример демонстрирует универсальный код работы с кешем для Internet Explorer и Firefox.

В Internet Explorer, если запрос возвращается из кеша без перепроверки, заголовок — пустая строка. Поэтому нужно сделать дополнительный запрос, который на самом деле никакой не дополнительный, т. к. текущий возвращен из кеша.

Ссылку на кешированый запрос сохраняем, т. к. если код ответа дополнительного запроса — «», то его тело станет пустой строкой («»), и нужно будет вернуться к кешированному объекту. Более эффективным, впрочем, будет не создавать новый объект , а сохранить данные из существующего и использовать заново его же.

Пример выше опирается на то, что сервер всегда выдает заголовок «», что верно для большинства конфигураций. В нем делается синхронный запрос. В асинхронном случае, проверка на Date и т. д. нужно делать после получения ответа в функции-обработчике .

Повторное использование объекта XmlHttpRequest

В Internet Explorer, если вызван после установки , может быть проблема с повторным использованием этого XmlHttpRequest.

Чтобы использовать заново XmlHttpRequest, сначала вызывайте метод , а затем — присваивайте . Это нужно потому, что IE неявно очищает объект XmlHttpRequest в методе , если его статус «».

Вызывать для перенаправления запроса на другой URL не нужно, даже если текущий запрос еще не завершился.

Утечки памяти

В Internet Explorer объект XmlHttpRequest принадлежит миру DOM/COM, а Javascript-функция — миру Javascript. Вызов r неявную круговую связь: ссылается на функцию через , а функция, через область видимости — видит (ссылается на) .

Невозможность обнаружить и оборвать такую связь во многих (до IE 6,7 редакции июня 2007?) версиях Internet Explorer приводит к тому, что XmlHttpRequest вместе с ответом сервера, функция-обработчик, и всё замыкание прочно оседают в памяти до перезагрузки браузера.

Чтобы этого избежать, ряд фреймворков (YUI, dojo…) вообще не ставят , а вместо этого через проверяют его каждые 10 миллисекунд. Это разрывает круговую связку <-> , и утечка памяти не грозит даже в самых глючных браузерах.

Получение нового содержимого

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

Пример такого слайд-шоу показан на рисунке ниже:

Содержимое этой страницы состоит из нескольких отдельных слайдов. Управление слайдами осуществляется щелчком по ссылкам «Пред» и «След», в результате чего загружается новое изображение со своей подписью. Запрос нового содержимого осуществляется посредством объекта XMLHttpRequest.

Для использования дизайна, подобного показанному, может быть несколько причин. При умелой реализации этот метод может позволить удерживать под контролем большие объемы содержимого, которое всегда готово для просмотра, но не перегружает страницу.

Лучшим способом реализации страницы такого типа будет использование объекта XMLHttpRequest. Таким образом, страница может запрашивать новое содержимое и обновлять только часть окна, не вызывая обновления всей страницы. А полные обновления плохи тем, что расходуют трафик, вызывают мигание страницы и заставляют пользователя прокручивать страницу обратно вверх. Все это может казаться мелочами, но такие мелочи отличают профессиональные, отполированные страницы от неуклюжих любительских.

Для создания примера, показанного на рисунке, сначала нам нужно выделить место для динамического содержимого. Для этого мы используем элемент <div>, который создает нам рамку с золотистым обрамлением и двумя ссылками внизу:

Ссылки вызывают функцию previousSlide() или nextSlide() в зависимости от направления просмотра слайдов. В обеих функциях используется счетчик, начальное значение которого равно 0, увеличивается до 5 и начинает новый цикл со значения 1. Код функций nextSlide() и previousSlide() выглядит следующим образом:

Обе функции используют еще одну функцию, goToNewSlide(), которая в действительности и выводит новое изображение:

Последний шаг в клиентской части — это скопировать полученные данные и элемент <div>, который отображает текущий слайд:

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

Чтобы придать этому примеру больше шика, изображения можно менять, используя эффект перехода. Например, новое изображение может постепенно проявляться, в то время как старое постепенно исчезает. Это одно из достоинств динамических страниц, использующих объект XMLHttpRequest — они могут полностью управлять способом представления содержимого.

HTTP-заголовки

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

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

Устанавливает заголовок запроса с именем и значением .

Например:

Ограничения на заголовки

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

не разрешено изменять их ради безопасности пользователей и для обеспечения корректности HTTP-запроса.

Поставленный заголовок нельзя снять

Ещё одной особенностью является то, что отменить невозможно.

Если заголовок определён, то его нельзя снять. Повторные вызовы лишь добавляют информацию к заголовку, а не перезаписывают его.

Например:

Возвращает значение заголовка ответа (кроме и ).

Например:

Возвращает все заголовки ответа, кроме и .

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

Между заголовками всегда стоит перевод строки в два символа (независимо от ОС), так что мы можем легко разделить их на отдельные заголовки. Значение заголовка всегда отделено двоеточием с пробелом . Этот формат задан стандартом.

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

Вот так (предполагается, что если два заголовка имеют одинаковое имя, то последний перезаписывает предыдущий):

Upload progress

The event triggers only on the downloading stage.

That is: if we something, first uploads our data (the request body), then downloads the response.

If we’re uploading something big, then we’re surely more interested in tracking the upload progress. But doesn’t help here.

There’s another object, without methods, exclusively to track upload events: .

It generates events, similar to , but triggers them solely on uploading:

  • – upload started.
  • – triggers periodically during the upload.
  • – upload aborted.
  • – non-HTTP error.
  • – upload finished successfully.
  • – upload timed out (if property is set).
  • – upload finished with either success or error.

Example of handlers:

Here’s a real-life example: file upload with progress indication:

Ограничения безопасности. Кросс-доменный 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. Кроме того, доступны еще модули, которые по необходимости правят урлы, разархивируют контент

Использование наддомена

Часто кроссбраузерные запросы — это

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

XMLHttpRequest Properties and Methods

Method Description
new XMLHttpRequest() Creates a new XMLHttpRequest object
open(method, url, async) Specifies the type of requestmethod: the type of request: GET or POSTurl: the file locationasync: true (asynchronous) or false (synchronous)
send() Sends a request to the server (used for GET)
send(string) Sends a request string to the server (used for POST)
onreadystatechange A function to be called when the readyState property changes
readyState The status of the XMLHttpRequest
0: request not initialized
1: server connection established
2: request received
3: processing request
4: request finished and response is ready
status 200: OK
404: Page not found
responseText The response data as a string
responseXML The response data as XML data

Событие onprogress в деталях

При обработке события есть ряд важных тонкостей.

Можно, конечно, их игнорировать, но лучше бы знать.

Заметим, что событие, возникающее при , имеет одинаковый вид на стадии отправки (в обработчике ) и при получении ответа (в обработчике ).

Оно представляет собой объект типа со свойствами:

Сколько байт уже переслано.

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

Если , то известно полное количество байт для пересылки, и оно хранится в свойстве .

Общее количество байт для пересылки, если известно.

А может ли оно быть неизвестно?

  • При отправке на сервер браузер всегда знает полный размер пересылаемых данных, так что всегда содержит конкретное количество байт, а значение всегда будет .
  • При скачивании данных – обычно сервер в начале сообщает их общее количество в HTTP-заголовке . Но он может и не делать этого, например если сам не знает, сколько данных будет или если генерирует их динамически. Тогда будет равно . А чтобы отличить нулевой размер данных от неизвестного – как раз служит , которое в данном случае равно .

Ещё особенности, которые необходимо учитывать при использовании :

Событие происходит при каждом полученном/отправленном байте, но не чаще чем раз в 50 мс.
Это обозначено в .

В процессе получения данных, ещё до их полной передачи, доступен , но он не обязательно содержит корректную строку.
Можно до окончания запроса заглянуть в него и прочитать текущие полученные данные

Важно, что при пересылке строки в кодировке UTF-8 кириллические символы, как, впрочем, и многие другие, кодируются 2 байтами. Возможно, что в конце одного пакета данных окажется первая половинка символа, а в начале следующего – вторая

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

Сработавшее событие не гарантирует, что данные дошли.
Событие срабатывает, когда данные отправлены браузером. Но оно не гарантирует, что сервер получил, обработал и записал данные на диск. Он говорит лишь о самом факте отправки.
Поэтому прогресс-индикатор, получаемый при его помощи, носит приблизительный и оптимистичный характер.

Описание интерфейса

Интерфейс XMLHttpRequest это интерфейс, который предоставляет функциональность для обмена данными между клиентом и сервером, он дает возможность получения данных по URL без необходимости полного обновления страницы. Интерфейс XMLHttpRequest широко используется в асинхронных запросах AJAX (от англ. Asynchronous Javascript and XML — «асинхронный JavaScript и XML»), что позволяет конкретной странице обновлять только её часть, не нарушая при этом работу пользователя. Кроме того, XMLHttpRequest имеет широкое использование при разработке одностраничных приложений (англ. single page application, SPA).

Несмотря на свое название, XMLHttpRequest можно использовать для получения любого типа данных, а не только XML, он поддерживает протоколы, отличные от HTTP (включая file и ftp).

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.

The basics

XMLHttpRequest has two modes of operation: synchronous and asynchronous.

Let’s see the asynchronous first, as it’s used in the majority of cases.

To do the request, we need 3 steps:

  1. Create :

    The constructor has no arguments.

  2. Initialize it, usually right after :

    This method specifies the main parameters of the request:

    • – HTTP-method. Usually or .
    • – the URL to request, a string, can be URL object.
    • – if explicitly set to , then the request is synchronous, we’ll cover that a bit later.
    • , – login and password for basic HTTP auth (if required).

    Please note that call, contrary to its name, does not open the connection. It only configures the request, but the network activity only starts with the call of .

  3. Send it out.

    This method opens the connection and sends the request to server. The optional parameter contains the request body.

    Some request methods like do not have a body. And some of them like use to send the data to the server. We’ll see examples of that later.

  4. Listen to events for response.

    These three events are the most widely used:

    • – when the request is complete (even if HTTP status is like 400 or 500), and the response is fully downloaded.
    • – when the request couldn’t be made, e.g. network down or invalid URL.
    • – triggers periodically while the response is being downloaded, reports how much has been downloaded.

Here’s a full example. The code below loads the URL at from the server and prints the progress:

Once the server has responded, we can receive the result in the following properties:

HTTP status code (a number): , , and so on, can be in case of a non-HTTP failure.
HTTP status message (a string): usually for , for , for and so on.
(old scripts may use )
The server response body.

We can also specify a timeout using the corresponding property:

If the request does not succeed within the given time, it gets canceled and event triggers.

URL search parameters

To add parameters to URL, like , and ensure the proper encoding, we can use URL object:

Запросы от имени пользователя

По умолчанию браузер не передаёт с запросом куки и заголовки для авторизации.

Чтобы браузер передал вместе с запросом куки и авторизацию, нужно добавить запросу xhr.withCredentials = true:

var xhr = new XMLHttpRequest(); 
xhr.withCredentials = true; 
xhr.open('POST', 'http://anywhere.com/req', true) ...

Далее – всё как обычно, дополнительных действий со стороны клиента не требуется.

Такой XMLHttpRequest с куками, естественно, требует от сервера больше разрешений, чем «анонимный».

Поэтому для запросов с withCredentials предусмотрено дополнительное подтверждение со стороны сервера.

При запросе с withCredentials сервер должен вернуть уже не один, а 2 заголовка:

  • Access-Control-Allow-Origin: домен
  • Access-Control-Allow-Credentials: true

Пример заголовков:

HTTP/1.1 200 OK Content-Type:text/html; 
charset=utf-8 
Access-Control-Allow-Origin: http://site.ru 
Access-Control-Allow-Credentials: true

Использование звёздочки * в Access-Control-Allow-Origin при этом запрещено.

Если этих заголовков не будет, то браузер не даст доступ к ответу сервера.

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

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

В следующем примере мы рассмотрим с вами как с помощью метода setRequestHeader() задать значение заголовка Content-Type (определяет MIME тип ресурса) HTTP запроса и отправить простой текст на сервер методом POST.

function postTextMessage(url, data) {
	let xhr = new XMLHttpRequest(); // инициализируем переменную новым объектом XMLHttpRequest

	xhr.open("POST", url); // определяем параметры для запроса на определенный адрес
	xhr.setRequestHeader("Content-Type", "text/plain;charset=utf-8"); // задаем значение заголовка HTTP запроса (текстовые данные в кодировке UTF-8)
	xhr.send(data); // отправляем запрос на сервер (используем значение параметра в качестве тела запроса)
}

В следующем примере мы рассмотрим с вами как с помощью метода setRequestHeader() задать значение заголовка Content-Type HTTP запроса и отправить данные формы на сервер методом POST.


function postFormData(url, data, callback) {
	let xhr = new XMLHttpRequest(); // инициализируем переменную новым объектом XMLHttpRequest

	xhr.open("POST", url); // определяем параметры для запроса на определенный адрес
	xhr.onreadystatechange = function() { // обработчик событий, вызываемый при запуске события readystatechange (при каждом изменении свойства readyState)
		// проверяем состояние запроса, числовой код состояния HTTP ответа и наличие переданной функции
		if (this.readyState === 4 && this.status == 200 && callback) {
			callback(xhr); // вызываем переданную в качестве параметра функ­цию
		}
	}
	xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); // задаем значение заголовка HTTP запроса (значения кодируются в кортежах с ключом, разделенных символом '&', с '=' между ключом и значением)
	xhr.send(data); // отправляем запрос на сервер (используем значение параметра в качестве тела запроса)
} 

В следующем примере мы рассмотрим с вами как с помощью метода setRequestHeader() задать значение заголовка Content-Type HTTP запроса и отправить данные в формате JSON на сервер методом POST.

function postJSONData(url, data, callback) {
	let xhr = new XMLHttpRequest(); // инициализируем переменную новым объектом XMLHttpRequest
	
	xhr.open("POST", url); // определяем параметры для запроса на определенный адрес
	xhr.onreadystatechange = function() { // обработчик событий, вызываемый при запуске события readystatechange (при каждом изменении свойства readyState)
		// проверяем состояние запроса, числовой код состояния HTTP ответа и наличие переданной функции
		if (this.readyState === 4 && this.status == 200 && callback) {
			callback(xhr); // вызываем переданную в качестве параметра функ­цию
		}
	}
	xhr.setRequestHeader("Content-Type", "application/json"); // задаем значение заголовка HTTP запроса (данные в формате JSON)
	xhr.send(data); // отправляем запрос на сервер (используем значение параметра в качестве тела запроса)
}

JavaScript XMLHttpRequest

§Monitoring Download and Upload Progress

Network connectivity can be intermittent, and latency and bandwidth
are highly variable. So how do we know if an XHR request has succeeded,
timed out, or failed? The XHR object provides a convenient API for
listening to progress events (), which indicate the current status
of the request.

Event type Description

Times fired

loadstart Transfer has begun

once

progress Transfer is in progress

zero or more

error Transfer has failed

zero or once

abort Transfer is terminated

zero or once

load Transfer is successful

zero or once

loadend Transfer has finished once

Table 15-1. XHR progress events

Each XHR transfer begins with a loadstart and finishes with a
loadend event, and in between, one or more additional events are
fired to indicate the status of the transfer. Hence, to monitor progress
the application can register a set of JavaScript event listeners on the
XHR object:

var xhr = new XMLHttpRequest();
xhr.open('GET','/resource');
xhr.timeout = 5000; 

xhr.addEventListener('load', function() { ... }); 
xhr.addEventListener('error', function() { ... }); 

var onProgressHandler = function(event) {
  if(event.lengthComputable) {
    var progress = (event.loaded / event.total) * 100; 
    ...
  }
}

xhr.upload.addEventListener('progress', onProgressHandler); 
xhr.addEventListener('progress', onProgressHandler); 
xhr.send();
  1. Set request timeout to 5,000 ms (default: no timeout)

  2. Register callback for successful request

  3. Register callback for failed request

  4. Compute transfer progress

  5. Register callback for upload progress events

  6. Register callback for download progress events

Either the load or error event will fire once to
indicate the final status of the XHR transfer, whereas the
progress event can fire any number of times and provides a
convenient API for tracking transfer status: we can compare the
loaded attribute against total to estimate the amount
of transferred data.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector