XMLHttpRequest
— это объект JavaScript, созданный Microsoft и адаптированный Mozilla. Вы можете использовать его для простой передачи данных через HTTP. Несмотря на свое название, он может быть использован не только для XML документов, но и, например, для JSON.
Оставшаяся часть статьи может содержать информацию, специфичную для Gecko или привилегированного кода, такого как дополнения.
В Gecko этот объект реализует интерфейсы nsIJSXMLHttpRequest
и nsIXMLHttpRequest
. Недавние версии Gecko содержат некоторые изменения для этого объекта (см. XMLHttpRequest changes for Gecko1.8).
Основы использования
Использовать XMLHttpRequest
очень просто. Вы создаёте экземпляр объекта, открываете URL и отправляете запрос. Статус HTTP-ответа, так же как и возвращаемый документ, доступны в свойствах объекта запроса.
data.inputEncoding
(где data —
ненулевой объект, переданный в send()
). Если не определено, то используется UTF-8.Пример
var req = new XMLHttpRequest(); req.open('GET', 'https://www.mozilla.org/', false); req.send(null); if(req.status == 200) dump(req.responseText);
Пример без http протокола
var req = new XMLHttpRequest(); req.open('GET', 'file:///home/user/file.json', false); req.send(null); if(req.status == 0) dump(req.responseText);
status
и пустую строчку в statusText
. См. баг 331610 для подробной информации.Асинхронное использование
Если вы собираетесь использовать XMLHttpRequest
из дополнения, вы должны позволить ему загружаться асинхронно. Во время асинхронного использования вы получаете отзыв после загрузки данных, что позволяет браузеру продолжать работу пока ваш запрос обрабатывается.
Пример
var req = new XMLHttpRequest(); req.open('GET', 'https://www.mozilla.org/', true); /* Третий аргумент true означает асинхронность */ req.onreadystatechange = function (aEvt) { if (req.readyState == 4) { if(req.status == 200) dump(req.responseText); else dump("Error loading page\n"); } }; req.send(null);
Наблюдение за прогрессом
XMLHttpRequest
предоставляет возможность отлавливать некоторые события которые могут возникнуть во время обработки запроса. Включая периодические уведомления о прогрессе, сообщения об ошибках и так далее.
Если к примеру вы желаете предоставить информацию пользователю о прогрессе получения документа, вы можете использовать код вроде этого:
function onProgress(e) { var percentComplete = (e.position / e.totalSize)*100; ... } function onError(e) { alert("Error " + e.target.status + " occurred while receiving the document."); } function onLoad(e) { // ... } // ... var req = new XMLHttpRequest(); req.onprogress = onProgress; req.open("GET", url, true); req.onload = onLoad; req.onerror = onError; req.send(null);
Атрибуты события onprogress
: position
и totalSize
, отображают соотвественно текущие количество принятых байтов и количество ожидаемых байтов.
Все эти события имеют свои target
атрибуты установленные в соответствии с XMLHttpRequest
.
target
, currentTarget
и this
у объекта события на правильные объекты во время вызова обработчика событий для XML документов представленных в XMLDocument
. См. баг 198595 для деталей.Другие Свойства и Методы
В дополнение к свойствам и методам описанным выше, ниже следуют другие полезные свойства и методы для объекта запроса.
responseXML
Если вы загрузили XML документ свойство responseXML
будет содержать документ в виде XmlDocument
объекта которым вы можете манипулировать используя DOM методы. Если сервер отправляет правильно сформированные XML документы но не устанавливает Content-Type заголовок для него, вы можете использовать overrideMimeType()
для того чтобы документ был обработан как XML. Если сервер не отправляет правильно сформированного документа XML, responseXML
вернет null независимо от любых перезаписей Content-Type заголовка.
overrideMimeType()
Этот метод может быть использован для обработки документа особенным образом. Обычно вы будете использовать его, когда запросите responseXML,
и сервер отправит вам XML, но не отправит правильного Content-Type заголовка.
send()
.var req = new XMLHttpRequest(); req.open('GET', 'https://www.mozilla.org/', true); req.overrideMimeType('text/xml'); req.send(null);
setRequestHeader()
Этот метод может быть использован чтобы установить HTTP заголовок в запросе до его отправки.
open()
.var req = new XMLHttpRequest(); req.open('GET', 'https://www.mozilla.org/', true); req.setRequestHeader("X-Foo", "Bar"); req.send(null);
getResponseHeader()
Этот метод может быть использован для получения HTTP заголовка из ответа сервера.
var req = new XMLHttpRequest(); req.open('GET', 'https://www.mozilla.org/', false); req.send(null); dump("Content-Type: " + req.getResponseHeader("Content-Type") + "\n");
abort()
Этот метод может быть использован чтобы отменить обрабатываемый запрос.
var req = new XMLHttpRequest(); req.open('GET', 'https://www.mozilla.org/', false); req.send(null); req.abort();
mozBackgroundRequest
Это свойство может быть использовано чтобы уберечь от всплытия аутентификации и неправильных диалогов сертификации в ответ на запрос. Также запрос не будет отменен при закрытии его окна, которому он принадлежит. Это свойство работает только для кода chrome.
var req = new XMLHttpRequest(); req.mozBackgroundRequest = true; req.open('GET', 'https://www.mozilla.org/', true); req.send(null);
Using from XPCOM components
XMLHttpRequest cannot be instantiated using the XMLHttpRequest()
constructor from a JavaScript XPCOM component. 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 QueryInterface the component to an nsIEventTarget
in order to add event listeners, but chances are in C++ using a channel directly would be better.
Limited number of simultaneous XMLHttpRequest connections
The about:config preference: network.http.max-persistent-connections-per-server limits the number of connections. In Firefox 3 this value is 6 by default, previous versions use 2 as the default. Some interactive web pages using xmlHttpRequest may keep a connection open. Opening two or three of these pages in different tabs or on different windows may cause the browser to hang in such a way that the window no longer repaints and browser controls don't respond.
Binary Content
Although less typical than sending/receiving character-oriented content, XMLHttpRequest
can be used to send and receive binary content.
Retrieving binary content
// Fetches BINARY FILES synchronously using XMLHttpRequest function load_binary_resource(url) { var req = new XMLHttpRequest(); req.open('GET', url, false); //XHR binary charset opt by Marcus Granado 2006 [https://mgran.blogspot.com] req.overrideMimeType('text/plain; charset=x-user-defined'); req.send(null); if (req.status != 200) return ''; return req.responseText; } var filestream = load_binary_resource(url); // x is the offset (i.e. position) of the byte in the returned binary file stream. The valid range for x is from 0 up to filestream.length-1. var abyte = filestream.charCodeAt(x) & 0xff; // throw away high-order byte (f7)
See downloading binary streams with XMLHttpRequest for a detailed explanation. See also downloading files.
Sending binary content
This example POSTs binary content asynchronously. aBody is some data to send.
var req = new XMLHttpRequest(); req.open("POST", url, true); // set headers and mime-type appropriately req.setRequestHeader("Content-Length", 741); req.sendAsBinary(aBody);
You can also send binary content by passing an instance of interface nsIFileInputStream to req.send()
. In that case, there is not need to set the Content-Length request header:
// Make a stream from a file. The file variable holds an nsIFile var stream = Components.classes["@mozilla.org/network/file-input-stream;1"] .createInstance(Components.interfaces.nsIFileInputStream); stream.init(file, 0x04 | 0x08, 0644, 0x04); // file is an nsIFile instance // Try to determine the MIME type of the file var mimeType = "text/plain"; try { var mimeService = Components.classes["@mozilla.org/mime;1"].getService(Components.interfaces.nsIMIMEService); mimeType = mimeService.getTypeFromFile(file); // file is an nsIFile instance } catch(e) { /* eat it; just use text/plain */ } // Send var req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"] .createInstance(Components.interfaces.nsIXMLHttpRequest); req.open('PUT', url, false); /* synchronous! */ req.setRequestHeader('Content-Type', mimeType); req.send(stream);
Bypassing cache
Normally, XMLHttpRequest
attempts to retrieve content from local cache. To bypass this attempt, do the following:
var req = new XMLHttpRequest(); req.open('GET', url, false); req.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE; req.send(null);
An alternative approach to bypassing cache, as described here:
var req = new XMLHttpRequest(); req.open("GET", url += (url.match(/\?/) == null ? "?" : "&") + (new Date()).getTime(), false); req.send(null);
This appends a timestamp URL parameter to the URL, taking care to insert a ? or & as appropriate. For example, https://foo.com/bar.html becomes https://foo.com/bar.html?12345 and https://foo.com/bar.html?foobar=baz becomes https://foo.com/bar.html?foobar=baz&12345. Since local cache is indexed by URL, the idea is that every URL used by XMLHttpRequest is unique, bypassing the cache.
Downloading JSON and JavaScript in extensions
Extensions shouldn't use eval() on JSON or JavaScript downloaded from the web. See Downloading JSON and JavaScript in extensions for details.