Xhr что это
Перейти к содержимому

Xhr что это

  • автор:

XMLHttpRequest

XMLHttpRequest это API, который предоставляет клиенту функциональность для обмена данными между клиентом и сервером. Данный API предоставляет простой способ получения данных по ссылке без перезагрузки страницы. Это позволяет обновлять только часть веб-страницы не прерывая пользователя. XMLHttpRequest используется в AJAX запросах и особенно в single-page приложениях.

XMLHttpRequest изначально был разработан Microsoft и позже заимствован Mozilla, Apple, и Google. Сейчас он стандартизирован WHATWG. Несмотря на своё название, XMLHttpRequest может быть использован для получения любых типов данных, не только XML, и поддерживает протоколы помимо HTTP (включая file и ftp).

Чтобы начать работать с XMLHttpRequest , выполните этот код:

var myRequest = new XMLHttpRequest();

более детальное описание создание объекта, можно увидеть в разделе Using XMLHttpRequest.

Список методов объекта

XMLHttpRequest(JSObject objParameters);
void abort();
DOMString getAllResponseHeaders();
DOMString? getResponseHeader(DOMString header);
void open(DOMString method, DOMString url, optional boolean async, optional DOMString? user, optional DOMString? password);
void overrideMimeType(DOMString mime);
void send(); void send(ArrayBufferView data); void send(Blob data); void send(Document data); void send(DOMString? data); void send(FormData data);
void setRequestHeader(DOMString header, DOMString value);
Нестандартные методы
[noscript] void init(in nsIPrincipal principal, in nsIScriptContext scriptContext, in nsPIDOMWindow ownerWindow);
[noscript] void openRequest(in AUTF8String method, in AUTF8String url, in boolean async, in AString user, in AString password);
void sendAsBinary(in DOMString body); Устарело

Поля объекта

Callback — функция, которая вызывается всякий раз, когда поле readyState меняет своё значение . Callback выполняется в потоке работы приложения.

Внимание: Он не должен использоваться в синхронных запросах, и не должен выполняться из нативного кода (? must not be used from native code).

Тело сущности запроса. Согласно полю responseType , может быть ArrayBuffer , Blob , Document , JavaScript объектом (для «json»), или строкой. Равно null если запрос не завершён или окончен с ошибкой.

Может использоваться для определения типа ответа.

Похоже на поле «text» , но только находится в потоке(streaming). Это значит, что значение доступно только в промежуток времени между событиями прогресса ( «progress» event), и содержит данные которые пришли из последнего события прогресса.

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

Работает только в Firefox.

Похоже на поле «arraybuffer» , но только находится в потоке(streaming). Это значит, что значение доступно только в промежуток времени между событиями прогресса ( «progress» event), и содержит данные которые пришли из последнего события прогресса.

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

Работает только в Firefox.

Note: Starting with Gecko 11.0 , as well as WebKit build 528, these browsers no longer let you use the responseType attribute when performing synchronous requests. Attempting to do so throws an NS_ERROR_DOM_INVALID_ACCESS_ERR exception. This change has been proposed to the W3C for standardization.

Ответ является объектом DOM Document , или null в случае если запрос окончился ошибкой, или ответ не получен полностью, или если ответ невозможно распарсить как XML или HTML. Ответ парсится как если бы это был text/xml stream. Когда значение responseType равно «document» и запрос выполнен асинхронно, ответ парсится как text/html stream.

Примечание: Если сервер не работает с заголовком (не присылает в ответе) «Content-type: text/xml» , то можно использовать метод overrideMimeType() для того чтобы парсить получаемый ответ как XML.

Время в миллисекундах, после которого запрос будет отменён. Значение 0 (по умолчанию) значит что таймаута не будет. Никогда.

Примечание: Вы можете не использовать поле timeout для синхронных запросов из owning window.

Колбэк-функция которая будет вызвана в случае таймаута.

Определяет что cross-site запрос, согласно Access-Control должен использовать авторизацию (креды для логина и пароля) через куки, или заголовок с авторизационными данными. По умолчанию false.

Примечание: Не влияет на same-site запросы.

Примечание: Начиная с Gecko 11.0 , Gecko больше не позволяет использовать поле withCredentials при выполнении синхронных запросов. Попытка выполнить это выбрасывает NS_ERROR_DOM_INVALID_ACCESS_ERR исключение.

Нестандартные свойства

Если значение равно true, запрос отправляется без куки и заголовков авторизации.

Если значение равно true, same origin policy не будут использоваться в запросе (кроссдоменный запрос не сработает).

Этот метод не может быть вызван из контекста страницы. Для того чтобы воспользоваться им нужны повышенные привелегии (elevated privileges).

Флаг, означающий что запрос от пользователя надо скрыть. Для пользователя не появится никаких сообщений и/или оповещений что запрос вообще был.

В случае, если для продолжения запроса нужна какая-то аутентификация, и в других случаях было бы отображено оповещение, этот запрос просто не сработает.

Note: Этот флаг должен быть выставлен до вызова метода open() .

This Gecko-only feature was removed in Firefox/Gecko 22. Please use Server-Sent Events (en-US) , Web Sockets, or responseText from progress events instead.

Indicates whether or not the response is expected to be a stream of possibly multiple XML documents. If set to true , the content type of the initial response must be multipart/x-mixed-replace or an error will occur. All requests must be asynchronous.

This enables support for server push; for each XML document that’s written to this request, a new XML DOM document is created and the onload handler is called between documents.

Note: When this is set, the onload handler and other event handlers are not reset after the first XMLdocument is loaded, and the onload handler is called after each part of the response is received.

Конструктор

XMLHttpRequest()

Конструктор создаёт объект XMLHttpRequest. Он должен быть вызван перед обращением к любому методу класса.

Gecko/Firefox 16 добавляет нестандартные параметры в конструктор, для лучшего взаимодействия с режимом инкогнито, (смотри Bug 692677). Установка флага mozAnon в значение true создаёт сущность AnonXMLHttpRequest() описанную в XMLHttpRequest спецификации, но не реализованную не в одном из браузеров (информация сентября 2012).

XMLHttpRequest ( JSObject objParameters );
Параметры (нестандартные)

Вы можете использовать два флага:

Boolean: Использование этого флага уберёт из запроса заголовки origin, и user credentials. Кроме этого, куки не будут отправлены в запросе, если только они не будут добавлены к запросу специально, через метод setRequestHeader.

Boolean: Если выставить этот флаг в значение true то это позволит делать cross-доменные запросы без необходимости получения специальных заголовков со стороны сервера (CORS). Для использования этого флага необходимо использовать дополнительный флаг* mozAnon: true , поскольку для отправки запроса на другой домен, нельзя использовать куки и креды пользователя. Этот флаг работает только с привилегированными (одобренными) приложениями; он не сработает с произвольно загруженными страницами.*

Методы

abort()

Отменяет запрос, если он был отправлен.

getAllResponseHeaders()

DOMString getAllResponseHeaders();

Возвращает все заголовки ответа как строку, или null если ответ не был получен. Для multypart запросов возвращает заголовки текущей части запроса, а не всего канала.

getResponseHeader()

DOMString? getResponseHeader(DOMString header);

Возвращает значение указанного заголовка из полученного ответа, или null в случает если ответ не получен, или такого заголовка в ответе нет. Возвращаемая строка имеет кодировку UTF.

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

open()

Инициализирует запрос. Этот метод может (и должен) быть вызван из JavaScript-кода; если необходимо вызвать запрос из нативного кода, то нужно использовать метод openRequest() .

Примечание: Вызов этого метода из активного запроса (если метод open() или openRequest() уже были вызваны ) эквивалентно вызову метода abort() .

void open( DOMString method, DOMString url, optional boolean async, optional DOMString user, optional DOMString password );
Параметры

HTTP метод отправки сообщения — «GET», «POST», «PUT», «DELETE», и проч.. Ignored for non-HTTP(S) URLs.

URL адрес, на который будет отправлено сообщение.

Необязательный boolean параметр, по умолчанию равный true . Определяет, будет ли запрос отправлен асинхронно. Если значение равно false , метод send() вернёт ответ в общем потоке работы приложения (иначе говоря, приложение зависнет на некоторое время), в противном случае, ответ может быть получен только при помощи определённых обработчиков событий. В случае, если используется отправка multipart запроса, то этот атрибут должен быть true , или будет выброшено исключение.

Примечание: Начиная с Gecko 30.0, синхронные запросы объявлены как deprecated, в силу того что все пользователи недовольны тем, что приложение «зависает».

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

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

overrideMimeType()

Переопределяет MIME тип, получаемый от сервера. Это может быть использовано, например, для того чтобы получить и распарсить данные в формате text/xml, даже, если сервер сообщает что это не так. Этот метод должен быть вызван перед вызовом метода send() .

void overrideMimeType(DOMString mimetype);

send()

Отправляет запрос. Если запрос асинхронный (а по умолчанию это так), этот метод вернёт значение сразу после того как метод вызван.

Примечание: в этом случае, в ответе не будет содержаться информации, которая пришла с сервера, поскольку она ещё не пришла. Для того чтобы получить эту информацию, нужно слушать события загрузки, или использовать promise.

Если запрос синхронный, то метод вернёт значение только после того, как придёт запрос от сервера.

Примечание: все необходимые обработчики событий должны быть установлены перед вызовом send() .

Примечание: Лучше не использовать параметр ArrayBuffer. Сейчас он не входит в спецификацию XMLHttpRequest . Вместо него можно использовать ArrayBufferView (смотри таблицу совместимости для различных версий).

void send(); void send(ArrayBuffer data); void send(ArrayBufferView data); void send(Blob data); void send(Document data); void send(DOMString? data); void send(FormData data);
Примечания

Если тип data — Document , то он будет сериализован перед отправкой. Firefox до версии 3 всегда отправляет такой запрос в кодировке UTF-8; Firefox 3 отправляет данные в той кодировке, которая указаны в body.xmlEncoding , или UTF-8 если такой информации нет.

If it’s an nsIInputStream , it must be compatible with nsIUploadChannel ‘s setUploadStream() method. In that case, a Content-Length header is added to the request, with its value obtained using nsIInputStream ‘s available() method. Any headers included at the top of the stream are treated as part of the message body. The stream’s MIMEtype should be specified by setting the Content-Type header using the setRequestHeader() method prior to calling send() .

The best way to send binary content (like in files upload) is using an ArrayBufferView (en-US) or Blobs (en-US) in conjuncton with the send() method. However, if you want to send a stringifiable (en-US) raw data, use the sendAsBinary() (en-US) method instead, or the StringView Non native typed arrays superclass.

setRequestHeader()

Устанавливает значение заголовка HTTP-запроса. Вы должны вызвать setRequestHeader() после open() , но перед send() . Если данный метод вызывается несколько раз с одним и тем же заголовком, все значения объединяются в один заголовок запроса.

void setRequestHeader( DOMString header, DOMString value );
Параметры

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

Значение, заданное как тело заголовка.

Нестандартные методы

init()

Инициализирует объект для использования с C++ кодом.

Предупреждение: Внимание: Этот метод нельзя вызывать из JavaScript.

[noscript] void init( in nsIPrincipal principal, in nsIScriptContext scriptContext, in nsPIDOMWindow ownerWindow );
Параметры

Принцип, используемый для запроса; не должен быть null .

Контекст скрипта, используемого для запроса; не должен быть null .

Окно, связанное с запросом; может быть null .

openRequest()

Инициализирует запрос. Этот метод должен использоваться из собственного кода; для инициализации запроса из кода JavaScript вместо этого используйте используйте open() метод. Смотрите документацию для open() .

sendAsBinary() Устарело

Вариант метода send() который посылает бинарные данные.

Примечание: Этот нестандартный метод считается устарелым по состоянию на Gecko 31, и со временем будет удалён. Взамен может использоваться стандарт метода send(Blob data).

void sendAsBinary( in DOMString body );

Данный метод используется в сочетании с методом readAsBinaryString, который присутствует в FileReader (en-US) API, и позволяет прочитать и загрузить файл любого типа (en-US) и превратить необработанные данные в JSON-строку (en-US) .

Параметры

Тело запроса в виде DOMstring. Эти данные конвертированы в строку с однобайтовыми символами с помощью усечения (удаления байта с высоким порядком в каждом символе).

sendAsBinary() polyfill

Since sendAsBinary() is an experimental feature, here is a polyfill for browsers that don’t support the sendAsBinary() method but support typed arrays (en-US) .

/*\ |*| |*| :: XMLHttpRequest.prototype.sendAsBinary() Polyfill :: |*| |*| https://developer.mozilla.org/ru/docs/DOM/XMLHttpRequest#sendAsBinary() |*| \*/ if (!XMLHttpRequest.prototype.sendAsBinary)  XMLHttpRequest.prototype.sendAsBinary = function (sData)  var nBytes = sData.length, ui8Data = new Uint8Array(nBytes); for (var nIdx = 0; nIdx  nBytes; nIdx++)  ui8Data[nIdx] = sData.charCodeAt(nIdx) & 0xff; > /* send as ArrayBufferView. */ this.send(ui8Data); /* . or as ArrayBuffer (legacy). this.send(ui8Data.buffer); */ >; > 

Примечание: It’s possible to build this polyfill putting two types of data as argument for send() : an ArrayBuffer (en-US) ( ui8Data.buffer – the commented code) or an ArrayBufferView (en-US) ( ui8Data , which is a typed array of 8-bit unsigned integers (en-US) – uncommented code). However, on Google Chrome, when you try to send an ArrayBuffer , the following warning message will appear: ArrayBuffer is deprecated in XMLHttpRequest.send(). Use ArrayBufferView instead. Another possible approach to send binary data is the StringView Non native typed arrays superclass in conjunction with the send() method.

Notes

  • By default, Firefox 3 limits the number of XMLHttpRequest connections per server to 6 (previous versions limit this to 2 per server). Some interactive web sites may keep an XMLHttpRequest connection open, so opening multiple sessions to such sites may result in the browser hanging in such a way that the window no longer repaints and controls don’t respond. This value can be changed by editing the network.http.max-persistent-connections-per-server preference in about:config .
  • From Gecko 7.0 headers set by setRequestHeader are sent with the request when following a redirect. Previously these headers would not be sent.
  • XMLHttpRequest is implemented in Gecko using the nsIXMLHttpRequest , nsIXMLHttpRequestEventTarget , and nsIJSXMLHttpRequest interfaces.
  • When a request reaches its timeout value, a «timeout» event is raised.
Events

onreadystatechange as a property of the XMLHttpRequest instance is supported in all browsers.

Since then, a number of additional event handlers were implemented in various browsers ( onload , onerror , onprogress , etc.). These are supported in Firefox. In particular, see nsIXMLHttpRequestEventTarget and Using XMLHttpRequest.

More recent browsers, including Firefox, also support listening to the XMLHttpRequest events via standard addEventListener APIs in addition to setting on* properties to a handler function.

Permissions

When using System XHR via the mozSystem property, for example for Firefox OS apps, you need to be sure to add the systemXHR permission into your manifest file. System XHR can be used in privileged or certified apps.

"permissions":  "systemXHR":> > 

Совместимость с браузерами

BCD tables only load in the browser

See also

  • MDN articles about XMLHttpRequest:
    • AJAX — Getting Started
    • Using XMLHttpRequest
    • HTML in XMLHttpRequest
    • FormData
    • W3C: XMLHttpRequest (base features)
    • W3C: XMLHttpRequest (latest editor’s draft with extensions to the base functionality, formerly XMLHttpRequest Level 2
    • Microsoft documentation
    • Apple developers’ reference
    • Components.utils.importGlobalProperties
    • nsIXMLHttpRequest [en-US]

    Found a content problem with this page?

    • Edit the page on GitHub.
    • Report the content issue.
    • View the source on GitHub.

    This page was last modified on 3 авг. 2023 г. by MDN contributors.

    Your blueprint for a better internet.

    MDN

    Support

    • Product help
    • Report an issue

    Our communities

    Developers

    • Web Technologies
    • Learn Web Development
    • MDN Plus
    • Hacks Blog
    • Website Privacy Notice
    • Cookies
    • Legal
    • Community Participation Guidelines

    Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
    Portions of this content are ©1998– 2023 by individual mozilla.org contributors. Content available under a Creative Commons license.

    Основы XMLHttpRequest

    Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

    Более новая информация по этой теме находится на странице https://learn.javascript.ru/xmlhttprequest.

    Объект XMLHttpRequest (или, как его кратко называют, «XHR») даёт возможность из JavaScript делать HTTP-запросы к серверу без перезагрузки страницы.

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

    Использовать его очень просто.

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

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

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

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

    phones.json

    var http = require('http'); var url = require('url'); var querystring = require('querystring'); var static = require('node-static'); var file = new static.Server('.', < cache: 0 >); function accept(req, res) < if (req.url == '/phones.json') < // искусственная задержка для наглядности setTimeout(function() < file.serve(req, res); >, 2000); > else < file.serve(req, res); >> // ------ запустить сервер ------- if (!module.parent) < http.createServer(accept).listen(8080); >else
           

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

    Настроить: open

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

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

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

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

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

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

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

    Вызов open не открывает соединение

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

    Отослать данные: 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 Текст ответа сервера.

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

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

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

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

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

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

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

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

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

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

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

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

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

    Полный пример в действии:

    XHR (XMLHttpRequest)

    XMLHttpRequest (XHR) это JavaScript API для создания AJAX запросов. Методы этого объекта предоставляют возможность отправки сетевых запросов между browser и server (en-US).

    Узнать больше

    Общие знания

    • Полезная информация о XMLHttpRequest
    • Разница между синхронной и асинхронной передачи сообщений

    Техническая информация

    • Объект XMLHttpRequest
    • документация MDN о том, как использовать XMLHttpRequest

    Found a content problem with this page?

    • Edit the page on GitHub.
    • Report the content issue.
    • View the source on GitHub.

    This page was last modified on 3 авг. 2023 г. by MDN contributors.

    Your blueprint for a better internet.

    MDN

    Support

    • Product help
    • Report an issue

    Our communities

    Developers

    • Web Technologies
    • Learn Web Development
    • MDN Plus
    • Hacks Blog
    • Website Privacy Notice
    • Cookies
    • Legal
    • Community Participation Guidelines

    Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
    Portions of this content are ©1998– 2023 by individual mozilla.org contributors. Content available under a Creative Commons license.

    XMLHttpRequest

    XMLHttpRequest – это встроенный в браузер объект, который даёт возможность делать HTTP-запросы к серверу без перезагрузки страницы.

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

    На сегодняшний день не обязательно использовать XMLHttpRequest , так как существует другой, более современный метод fetch .

    В современной веб-разработке XMLHttpRequest используется по трём причинам:

    1. По историческим причинам: существует много кода, использующего XMLHttpRequest , который нужно поддерживать.
    2. Необходимость поддерживать старые браузеры и нежелание использовать полифилы (например, чтобы уменьшить количество кода).
    3. Потребность в функциональности, которую fetch пока что не может предоставить, к примеру, отслеживание прогресса отправки на сервер.

    Что-то из этого списка звучит знакомо? Если да, тогда вперёд, приятного знакомства с XMLHttpRequest . Если же нет, возможно, имеет смысл изучать сразу Fetch.

    Основы

    XMLHttpRequest имеет два режима работы: синхронный и асинхронный.

    Сначала рассмотрим асинхронный, так как в большинстве случаев используется именно он.

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

    let xhr = new XMLHttpRequest(); // у конструктора нет аргументов
    xhr.open(method, URL, [async, user, password])
    • method – HTTP-метод. Обычно это «GET» или «POST» .
    • URL – URL, куда отправляется запрос: строка, может быть и объект URL.
    • async – если указать false , тогда запрос будет выполнен синхронно, это мы рассмотрим чуть позже.
    • user , password – логин и пароль для базовой HTTP-авторизации (если требуется).

    Заметим, что вызов open , вопреки своему названию, не открывает соединение. Он лишь конфигурирует запрос, но непосредственно отсылается запрос только лишь после вызова send .

    xhr.send([body])
    • load – происходит, когда получен какой-либо ответ, включая ответы с HTTP-ошибкой, например 404.
    • error – когда запрос не может быть выполнен, например, нет соединения или невалидный URL.
    • progress – происходит периодически во время загрузки ответа, сообщает о прогрессе.
    xhr.onload = function() < alert(`Загружено: $$`); >; xhr.onerror = function() < // происходит, только когда запрос совсем не получилось выполнить alert(`Ошибка соединения`); >; xhr.onprogress = function(event) < // запускается периодически // event.loaded - количество загруженных байт // event.lengthComputable = равно true, если сервер присылает заголовок Content-Length // event.total - количество байт всего (только если lengthComputable равно true) alert(`Загружено $из $`); >;

    Вот полный пример. Код ниже загружает /article/xmlhttprequest/example/load с сервера и сообщает о прогрессе:

    // 1. Создаём новый XMLHttpRequest-объект let xhr = new XMLHttpRequest(); // 2. Настраиваем его: GET-запрос по URL /article/. /load xhr.open('GET', '/article/xmlhttprequest/example/load'); // 3. Отсылаем запрос xhr.send(); // 4. Этот код сработает после того, как мы получим ответ сервера xhr.onload = function() < if (xhr.status != 200) < // анализируем HTTP-статус ответа, если статус не 200, то произошла ошибка alert(`Ошибка $: $`); // Например, 404: Not Found > else < // если всё прошло гладко, выводим результат alert(`Готово, получили $байт`); // response -- это ответ сервера > >; xhr.onprogress = function(event) < if (event.lengthComputable) < alert(`Получено $из $ байт`); > else < alert(`Получено $байт`); // если в ответе нет заголовка Content-Length > >; xhr.onerror = function() < alert("Запрос не удался"); >;

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

    status Код состояния HTTP (число): 200 , 404 , 403 и так далее, может быть 0 в случае, если ошибка не связана с HTTP. statusText Сообщение о состоянии ответа HTTP (строка): обычно OK для 200 , Not Found для 404 , Forbidden для 403 , и так далее. response (в старом коде может встречаться как responseText ) Тело ответа сервера.

    Мы можем также указать таймаут – промежуток времени, который мы готовы ждать ответ:

    xhr.timeout = 10000; // таймаут указывается в миллисекундах, т.е. 10 секунд

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

    URL с параметрами

    Чтобы добавить к URL параметры, вида ?name=value , и корректно закодировать их, можно использовать объект URL:

    let url = new URL('https://google.com/search'); url.searchParams.set('q', 'test me!'); // параметр 'q' закодирован xhr.open('GET', url); // https://google.com/search?q=test+me%21

    Тип ответа

    Мы можем использовать свойство xhr.responseType , чтобы указать ожидаемый тип ответа:

    • «» (по умолчанию) – строка,
    • «text» – строка,
    • «arraybuffer» – ArrayBuffer (для бинарных данных, смотрите в ArrayBuffer, бинарные массивы),
    • «blob» – Blob (для бинарных данных, смотрите в Blob),
    • «document» – XML-документ (может использовать XPath и другие XML-методы),
    • «json» – JSON (парсится автоматически).

    К примеру, давайте получим ответ в формате JSON:

    let xhr = new XMLHttpRequest(); xhr.open('GET', '/article/xmlhttprequest/example/json'); xhr.responseType = 'json'; xhr.send(); // тело ответа xhr.onload = function() < let responseObj = xhr.response; alert(responseObj.message); // Привет, мир! >;

    На заметку:

    В старом коде вы можете встретить свойства xhr.responseText и даже xhr.responseXML .

    Они существуют по историческим причинам, раньше с их помощью получали строки или XML-документы. Сегодня следует устанавливать желаемый тип объекта в xhr.responseType и получать xhr.response , как показано выше.

    Состояния запроса

    У XMLHttpRequest есть состояния, которые меняются по мере выполнения запроса. Текущее состояние можно посмотреть в свойстве xhr.readyState .

    Список всех состояний, указанных в спецификации:

    UNSENT = 0; // исходное состояние OPENED = 1; // вызван метод open HEADERS_RECEIVED = 2; // получены заголовки ответа LOADING = 3; // ответ в процессе передачи (данные частично получены) DONE = 4; // запрос завершён

    Состояния объекта XMLHttpRequest меняются в таком порядке: 0 → 1 → 2 → 3 → … → 3 → 4 . Состояние 3 повторяется каждый раз, когда получена часть данных.

    Изменения в состоянии объекта запроса генерируют событие readystatechange :

    xhr.onreadystatechange = function() < if (xhr.readyState == 3) < // загрузка >if (xhr.readyState == 4) < // запрос завершён >>;

    Вы можете наткнуться на обработчики события readystatechange в очень старом коде, так уж сложилось исторически, когда-то не было событий load и других. Сегодня из-за существования событий load/error/progress можно сказать, что событие readystatechange «морально устарело».

    Отмена запроса

    Если мы передумали делать запрос, можно отменить его вызовом xhr.abort() :

    xhr.abort(); // завершить запрос

    При этом генерируется событие abort , а xhr.status устанавливается в 0 .

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

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

    Другими словами, выполнение JavaScript останавливается на send() и возобновляется после получения ответа. Так ведут себя, например, функции alert или prompt .

    Вот переписанный пример с параметром async , равным false :

    let xhr = new XMLHttpRequest(); xhr.open('GET', '/article/xmlhttprequest/hello.txt', false); try < xhr.send(); if (xhr.status != 200) < alert(`Ошибка $: $`); > else < alert(xhr.response); >> catch(err) < // для отлова ошибок используем конструкцию try. catch вместо onerror alert("Запрос не удался"); >

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

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

    Из-за всего этого синхронные запросы используют очень редко. Мы более не будем рассматривать их.

    HTTP-заголовки

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

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

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

    xhr.setRequestHeader('Content-Type', 'application/json');

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

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

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

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

    Ещё одной особенностью 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» (независимо от ОС), так что мы можем легко разделить их на отдельные заголовки. Значение заголовка всегда отделено двоеточием с пробелом «: » . Этот формат задан стандартом.

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

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

    let headers = xhr .getAllResponseHeaders() .split('\r\n') .reduce((result, current) => < let [name, value] = current.split(': '); result[name] = value; return result; >, <>); // headers['Content-Type'] = 'image/png'

    POST, FormData

    Чтобы сделать POST-запрос, мы можем использовать встроенный объект FormData.

    let formData = new FormData([form]); // создаём объект, по желанию берём данные формы formData.append(name, value); // добавляем поле

    Мы создаём объект, при желании указываем, из какой формы form взять данные, затем, если нужно, с помощью метода append добавляем дополнительные поля, после чего:

    1. xhr.open(‘POST’, . ) – создаём POST -запрос.
    2. xhr.send(formData) – отсылаем форму серверу.
        

    Обычно форма отсылается в кодировке multipart/form-data .

    Если нам больше нравится формат JSON, то используем JSON.stringify и отправляем данные как строку.

    Важно не забыть поставить соответствующий заголовок Content-Type: application/json , многие серверные фреймворки автоматически декодируют JSON при его наличии:

    let xhr = new XMLHttpRequest(); let json = JSON.stringify(< name: "Вася", surname: "Петров" >); xhr.open("POST", '/submit') xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8'); xhr.send(json);

    Метод .send(body) весьма всеяден. Он может отправить практически что угодно в body , включая объекты типа Blob и BufferSource .

    Прогресс отправки

    Событие progress срабатывает только на стадии загрузки ответа с сервера.

    А именно: если мы отправляем что-то через POST -запрос, XMLHttpRequest сперва отправит наши данные (тело запроса) на сервер, а потом загрузит ответ сервера. И событие progress будет срабатывать только во время загрузки ответа.

    Если мы отправляем что-то большое, то нас гораздо больше интересует прогресс отправки данных на сервер. Но xhr.onprogress тут не поможет.

    Существует другой объект, без методов, только для отслеживания событий отправки: xhr.upload .

    Он генерирует события, похожие на события xhr , но только во время отправки данных на сервер:

    • loadstart – начало загрузки данных.
    • progress – генерируется периодически во время отправки на сервер.
    • abort – загрузка прервана.
    • error – ошибка, не связанная с HTTP.
    • load – загрузка успешно завершена.
    • timeout – вышло время, отведённое на загрузку (при установленном свойстве timeout ).
    • loadend – загрузка завершена, вне зависимости от того, как – успешно или нет.

    Примеры обработчиков для этих событий:

    xhr.upload.onprogress = function(event) < alert(`Отправлено $из $ байт`); >; xhr.upload.onload = function() < alert(`Данные успешно отправлены.`); >; xhr.upload.onerror = function() < alert(`Произошла ошибка во время отправки: $`); >;

    Пример из реальной жизни: загрузка файла на сервер с индикацией прогресса:

       

    Запросы на другой источник

    XMLHttpRequest может осуществлять запросы на другие сайты, используя ту же политику CORS, что и fetch.

    Точно так же, как и при работе с fetch , по умолчанию на другой источник не отсылаются куки и заголовки HTTP-авторизации. Чтобы это изменить, установите xhr.withCredentials в true :

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

    Детали по заголовкам, которые при этом необходимы, смотрите в главе fetch.

    Итого

    Типичный код GET-запроса с использованием XMLHttpRequest :

    let xhr = new XMLHttpRequest(); xhr.open('GET', '/my/url'); xhr.send(); xhr.onload = function() < if (xhr.status != 200) < // HTTP ошибка? // обработаем ошибку alert( 'Ошибка: ' + xhr.status); return; >// получим ответ из xhr.response >; xhr.onprogress = function(event) < // выведем прогресс alert(`Загружено $из $`); >; xhr.onerror = function() < // обработаем ошибку, не связанную с HTTP (например, нет соединения) >;

    Событий на самом деле больше, в современной спецификации они все перечислены в том порядке, в каком генерируются во время запроса:

    • loadstart – начало запроса.
    • progress – прибыла часть данных ответа, тело ответа полностью на данный момент можно получить из свойства responseText .
    • abort – запрос был прерван вызовом xhr.abort() .
    • error – произошла ошибка соединения, например неправильное доменное имя. Событие не генерируется для HTTP-ошибок как, например, 404.
    • load – запрос успешно завершён.
    • timeout – запрос был отменён по причине истечения отведённого для него времени (происходит, только если был установлен таймаут).
    • loadend – срабатывает после load , error , timeout или abort .

    События error , abort , timeout и load взаимно исключают друг друга – может произойти только одно из них.

    Наиболее часто используют события завершения загрузки ( load ), ошибки загрузки ( error ), или мы можем использовать единый обработчик loadend для всего и смотреть в свойствах объекта запроса xhr детали произошедшего.

    Также мы уже видели событие: readystatechange . Исторически оно появилось одним из первых, даже раньше, чем была составлена спецификация. Сегодня нет необходимости использовать его, так как оно может быть заменено современными событиями, но на него можно часто наткнуться в старом коде.

    Если же нам нужно следить именно за процессом отправки данных на сервер, тогда можно использовать те же события, но для объекта xhr.upload .

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

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