- Операторы
- Управляющие инструкции
- JS Объекты
- браузер BOM
- HTML DOM
- События
- HTML Объекты
- Промисы, async/await
- Сетевые запросы
- XMLHttpRequest
- Объекты URL
- Объект formData
- Fetch API
- Fetch API 2
- WebSocket
- Server Sent Events
- Бинарные данные и файлы
- Модули
- Классы
- Разное
Объект XMLHttpRequest
Объект XMLHttpRequest (или, сокращенно, XHR) дает возможность браузеру делать HTTP-запросы к серверу без перезагрузки страницы.
Все современные браузеры (IE7+, Firefox, Chrome, Safari и Opera) имеют встроенный объект XMLHttpRequest.
Синтаксис для создания объекта XMLHttpRequest:var xhr = new XMLHttpRequest();
В IE8 и IE9 поддержка XMLHttpRequest ограничена, но имеют свой объект XDomainRequest
, который реализовывал часть возможностей современного стандарта.
var XHR = ("onload" in new XMLHttpRequest()) ? XMLHttpRequest : XDomainRequest; var xhr = new XHR();
Создаём XMLHttpRequest и проверяем, поддерживает ли он событие onload
. Если нет, то это старый XMLHttpRequest, значит это IE8,9, и используем XDomainRequest
.
Для IE10+ обычный XMLHttpRequest уже является полноценным.
События
- onreadystatechange
-
Вызывается при изменении значения свойства readyState. Наиболее важен для обработки ситуации завершения запроса.
onreadystatechange
как свойствоXMLHttpRequest
поддерживается во всех браузерах.xhr.onreadystatechange =
илиобработчик
xhr.addEventListener( "readystatechange",
обработчик
)обработчик
- функция-обработчик события (можно указать анонимную функцию или ссылку на готовую). - onabort
Вызывается при прерывании запроса.
xhr.onabort =
обработчик
xhr.addEventListener( "abort",обработчик
)- onerror
Вызывается в случае завершения запроса по ошибке. Обратите внимание, что HTTP-коды состояния, такие как 404, не считаются ошибкой, поскольку сам ответ получен успешно. Однако это событие может породить отрицательный ответ сервера DNS или бесконечный цикл переа дресаций.
xhr.onerror =
обработчик
xhr.addEventListener( "error",обработчик
)- onload
Вызывается при успешном выполнении запроса. В обработчик передается объект
XMLHttpRequestProgressEvent
xhr.onload =
обработчик
xhr.addEventListener( "load",обработчик
)- onloadend
Вызывается в случае успешного или неудачного завершения запроса, после событий «load», «abort», «error» и «timeout».
xhr.onloadend =
обработчик
xhr.addEventListener( "loadend",обработчик
)- onloadstart
Вызывается с началом выполнения запроса.
xhr.onloadstart =
обработчик
xhr.addEventListener( "loadstart",обработчик
)- onprogress
Вызывается периодически (примерно раз в 50 миллисекунд) в ходе загрузки тела ответа.
xhr.onprogress =
обработчик
xhr.addEventListener( "progress",обработчик
)- ontimeout
Вызывается, если истекло время ожидания, определяемое свойством timeout, а ответ так и не был принят.
xhr.ontimeout =
обработчик
xhr.addEventListener( "timeout",обработчик
)
Свойства
- readyState
-
xhr.readyState
Состояние HTTP-запроса. В момент создания объекта
XMLHttpRequest
это свойство приобретает значение 0, а к моменту получения полного HTTP-ответа это значение возрастает до 4.Значение свойства readyState может уменьшаться, только если в процессе выполнения запроса был вызван метод
abort()
илиopen()
.Теоретически при каждом изменении значения этого свойства должен вызываться обработчик события
onreadystatechange
. Однако на практике событие гарантированно возникает, только когда свойство readyState получает значение 4. (События «progress», введенные спецификацией XHR2, обеспечивают более надежный способ слежения за ходом выполнения запроса.)Все состояния, по спецификации:
const unsigned short UNSENT = 0; // начальное состояние const unsigned short OPENED = 1; // вызван open const unsigned short HEADERS_RECEIVED = 2; // получены заголовки const unsigned short LOADING = 3; // загружается тело (получен очередной пакет данных) const unsigned short DONE = 4; // запрос завершён
Запрос проходит их в порядке 0 → 1 → 2 → 3 → … → 3 → 4, состояние 3 повторяется при каждом получении очередного пакета данных по сети.
- response
В спецификации XHR2 это свойство хранит ответ сервера. Тип свойства зависит от значения свойства
responseType.
Если
responseType
содержит пустую строку или строку «text», данное свойство содержит тело ответа в виде строки.Если
responseType
содержит строку «document», значением данного свойства будет объектDocument
, полученный в результате разбора XML- или HTML-документа в теле ответа.Если
responseType
содержит строку «arraybuffer», значением данного свойства будет объектArrayBuffer
, представляющий двоичные данные в теле ответа.Если
responseType
содержит строку «blob», значением данного свойства будет объектBlob
, представляющий двоичные данные в теле ответа.Если
responseType
содержит строку «json», значением данного свойства будет объект JSON, полученный путем парсинга JSON строки, полученной с сервера.- responseText
Если значение свойства
readyState
меньше 3, данное свойство будет содержать пустую строку.Если значение свойства
readyState
равно 3, данное свойство возвращает часть ответа, которая была принята к текущему моменту.Если значение свойства
readyState
равно 4, это свойство содержит полное тело ответа.Если в ответе имеется заголовок, определяющий кодировку символов в теле ответа, используется эта кодировка, в противном случае предполагается кодировка UTF-8.
- responseType
В спецификации XHR2 это свойство определяет тип ответа и тип свойства
response
. Прежде чем отправить запрос, необходимо для свойства xhr.responseType указать значение «text», «document», «arraybuffer», «blob» или «json». Значением по умолчанию является пустая строка, которая также является синонимом значения «text». Если установить это свойство вручную, последующие попытки обратиться к свойствамresponseText
иresponseXML
будут возбуждать исключения и для получения ответа сервера необходимо будет использовать свойствоresponse
, предусмотренное спецификацией XHR2.- responseXML
Ответ на запрос, который интерпретируется как XML- или HTML-документ и возвращается в виде объекта Document. Это свойство будет иметь значение null, если тело ответа еще не получено или оно не является допустимым XML или HTML-документом.
- status
HTTP-код состояния, полученный от сервера, такой как 200 – в случае успеха, 404 – в случае ошибки отсутствия документа или 0 – если сервер еще не прислал код состояния.
- statusText
Это свойство содержит текст, соответствующий HTTP-коду состояния в ответе. То есть, когда свойство status имеет значение 200, это свойство содержит строку «OK», а когда 404 – строку «Not Found». Это свойство содержит пустую строку, если сервер еще не прислал код состояния.
- timeout
Свойство, введенное спецификацией XHR2, определяющее предельное время ожидания ответа в миллисекундах. Если выполнение HTTP-запроса займет больше времени, чем указано в данном свойстве, он будет прерван и будет сгенерировано событие «timeout».
Это свойство можно установить только после вызова метода
open()
и перед вызовом методаsend()
.- upload
Свойство, введенное спецификацией XHR2, ссылающееся на объект XMLHttpRequestUpload, который определяет набор свойств регистрации обработчиков событий для слежения за процессом выгрузки тела HTTP-запроса.
- withCredentials
Свойство, введенное спецификацией XHR2, определяющее необходимость аутентификации при выполнении междоменного CORS-запроса и необходимость обработки заголовков cookie в CORS-ответах. По умолчанию имеет значение
false
.Как указано в спецификации www.w3.org/TR/cors/#omit-credentials-flag, withCredentials позволяет нам использовать в запросе к серверу user-credentials, т.е. cookie, аутентификационные данные и клиентские SSL-сертификаты.
Указание
withCredentials=true
необходимо не только для отправки «user-credentials» в запросе к серверу, но и для использования их из ответов от сервера.
xhr.response
xhr.responseText
xhr.responseType = [ "text" | "document" | "arraybuffer" | "blob" | "json" ]
xhr.responseXML
xhr.status
xhr.statusText
xhr.timeout = time
xhr.upload
xhr.withCredentials [ = true|false ]
Методы
- abort()
-
Возвращает объект XMLHttpRequest в исходное состояние, соответствующее значению 0 в свойстве
readyState
, и отменяет любые запланированные сетевые взаимодействия. Этот метод может потребоваться, например, если запрос выполняется слишком долго и надобность в получении ответа уже отпала. - 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" (не зависит от ОС), значение заголовка отделено двоеточием с пробелом ": ". Этот формат задан стандартом.
Таким образом, если хочется получить объект с парами заголовок-значение, то эту строку необходимо разбить и обработать.
- getResponseHeader()
-
Возвращает значение указанного заголовка header в HTTP-ответе или null, если заголовки вообще не были получены или если ответ не содержит требуемого заголовка
header
. Заголовки cookie и CORS отфильтровываются, и их нет смысла запрашивать. Если было принято несколько заголовков с указанным именем, значения этих заголовков объединяются в одну строку через запятую и пробел. Например:var header = xhr.getResponseHeader('Content-Type');
- open()
-
Этот метод инициализирует объект XMLHttpRequest и сохраняет свои аргументы для последующего использования методом
send()
.Аргумент method определяет HTTP-метод, используемый для отправки запроса. Среди наиболее устоявшихся методов можно назвать GET, POST и HEAD. Реализации могут также поддерживать методы CONNECT, DELETE, OPTIONS, PUT,TRACE и TRACK.
Аргумент url определяет URL-адрес, который является предметом запроса. Разрешение относительных URL-адресов производится обычным образом с использованием URL-адреса документа со сценарием. Политика общего происхождения требует, чтобы данный URL-адрес содержал те же имя хоста и номер порта, что и документ со сценарием, выполняющим запрос. Объект XHR2 позволяет выполнять междоменные запросы к серверам, поддерживающим заголовки CORS. В качестве URL можно использовать не только http/https, но и другие протоколы, например ftp:// и file://.
Если аргумент async указан и имеет значение
false
, запрос будет выполняться в синхронном режиме, и последующий вызовsend()
заблокирует работу сценария, пока ответ не будет получен полностью. Синхронные запросы рекомендуется использовать только в фоновых потоках выполнения.Необязательные аргументы user и pass определяют имя пользователя и пароль для HTTP-запроса.
Метод open() не выполняет запрос. Он его только конфигурирует. Для отправки запроса используется метод
send()
. - overrideMimeType()
-
Этот метод позволяет указать, что ответ сервера должен интерпретироваться в соответствии с указанным MIME-типом
mime
(и параметромcharset
, если он указан в определении типаmim
e), без учета значения заголовкаContent-Type
в ответе.Другими словами, метод позволяет переопределить тип получаемых с сервера данных. И даже существует специальная кодировка, которая специально была задумана для приема бинарных данных —
x-user-defined
(XMLHttpRequest автоматически преобразует все принятые данные в юникод). Поэтому простое добавление следующей строчки должно сделать большую часть работы.xhr.overrideMimeType('text/plain; charset=x-user-defined');
- send()
-
Именно этод метод открывает соединение и отправляет запрос на сервер. Если перед этим не вызывался метод
open()
или, обобщенно, если значение свойстваreadyState
не равно 1, метод send() возбуждает исключение. В противном случае он начинает выполнение HTTP-запроса,Если в предшествующем вызове метода
open()
аргументasync
имел значениеfalse
, данный метод блокируется и не возвращает управление, пока значение свойстваreadyState
не станет равно 4 и ответ сервера не будет получен полностью. В противном случае метод send() немедленно возвращает управление, а ответ сервера обрабатывается асинхронно, с помощью обработчиков событий.Аргумент body определяет «тело» запроса. Не у всякого запроса есть «тело», например у GET-запросов «тела» нет, а у POST – основные данные как раз передаются через body.
- setRequestHeader()
-
Определяет HTTP-заголовок с именем name и значением value, который должен быть включен в запрос, передаваемый последующим вызовом метода
send()
. Этот метод может вызываться, только когда свойствоreadyState
имеет значение 1, т. е. после вызова метода open(), но перед вызовом метода send().Если заголовок с именем «name» уже был определен, новым значением заголовка станет прежнее значение заголовка плюс запятая с пробелом и новое значение «value», переданное методу.
Если методу
open()
была передана информация об авторизации, объект XMLHttpRequest автоматически добавит заголовокAuthorization
. Однако этот заголовок может быть также добавлен методом setRequestHeader().Объект XMLHttpRequest автоматически устанавливает заголовки «Content-Length», «Date», «Referer» и «User-Agent» и не позволяет изменять их значения.
xhr.abort()
xhr.getAllResponseHeaders()
xhr.getResponseHeader( header )
xhr.open( method, url[, async, user, pass] )
xhr.overrideMimeType( mime )
xhr.send( [body] )
xhr.setRequestHeader( name, value )
POST, FormData
Чтобы сделать POST-запрос, можно использовать встроенный объект FormData.
Конструктор:
let formData = new FormData([form]); // создаём объект, по желанию берём данные формы <form>
Если передать в конструктор элемент HTML-формы form
, то создаваемый объект автоматически прочитает из неё поля.
Его особенность заключается в том, что методы для работы с сетью позволяют указать объект FormData
в свойстве тела запроса body
.
Он будет соответствующим образом закодирован и отправлен с заголовком Content-Type: form/multipart
.
То есть, для сервера это выглядит как обычная отправка формы.
Мы создаём объект, при желании указываем, из какой формы form
взять данные, затем, если нужно, с помощью метода append
добавляем дополнительные поля, после чего:
xhr.open('POST', ...)
– создаём POST
-запрос.xhr.send(formData)
– отсылаем форму серверу.
Методы объекта FormData
С помощью указанных ниже методов мы можем изменять поля в объекте FormData
:
formData.append(name, value)
– добавляет к объекту поле с именемname
и значениемvalue
,formData.append(name, blob, fileName)
– добавляет поле, как будто в форме имеется элемент<input type="file">
, третий аргументfileName
устанавливает имя файла (не имя поля формы), как будто это имя из файловой системы пользователя,formData.delete(name)
– удаляет поле с заданным именемname
,formData.get(name)
– получает значение поля с именемname
,formData.has(name)
– если существует поле с именемname
, то возвращаетtrue
, иначеfalse
Технически форма может иметь много полей с одним и тем же именем name
, поэтому несколько вызовов append
добавят несколько полей с одинаковыми именами.
Ещё существует метод set
, его синтаксис такой же, как у append
. Разница в том, что .set
удаляет все уже имеющиеся поля с именем name
и только затем добавляет новое. То есть этот метод гарантирует, что будет существовать только одно поле с именем name
, в остальном он аналогичен .append
:
formData.set(name, value)
,formData.set(name, blob, fileName)
.
Поля объекта formData
можно перебирать, используя цикл for..of
:
let formData = new FormData(); formData.append('key1', 'value1'); formData.append('key2', 'value2'); formData.append('key3', 'value3'); var s=''; // Список пар ключ/значение for(let [name, value] of formData) {s += `${name} = ${value}` + '\n'; } Alert(s);
Совместимость с браузерами
Особенность | |||||
Basic support | 1,0 | 7,0 | 1,0 | 1,2 | Да |
send(ArrayBuffer) | 9,0 | 10,0 | 9,0 | ? | 11,60 |
send(Blob) | 7,0 | 10,0 | 3,6 | ? | 12,0 |
send(FormData) | 6,0 | 10,0 | 4,0 | ? | 12,0 |
response | 10,0 | 10,0 | 6,0 | Да | 11,60 |
responseType = 'arraybuffer' | 10,0 | 10,0 | 6,0 | Да | 11,60 |
responseType = 'blob' | 19,0 | 10,0 | 6,0 | Да | 12,0 |
responseType = 'document' | 18,0 | 10,0 | 11,0 | 6,1 | Нет |
responseType = 'json' | 31,0 | Нет | 10,0 | Да | 12,0 (17,0) |
Progress Events | 7,0 | 10,0 | 3,5 | Да | 12,0 |
withCredentials | 3,0 | 10,0 | 3,5 | 4,0 | 12,0 |
timeout | 29,0 | 8,0 | 12,0 | Да | 12,0 (16,0) |
Примеры
Пример 1
<script> function loadXMLDoc(but) { but.disabled = true; var XHR = ("onload" in new XMLHttpRequest()) ? XMLHttpRequest : XDomainRequest; var xhr = new XHR(); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { document.getElementById("myDiv").innerHTML=xhr.responseText; } } xhr.open("GET","xhr/xmlhttp_info.txt",true); xhr.send(); } </script> <h2>Использование объекта XMLHttpRequest</h2> <div id="myDiv"></div> <button type="button" onclick="loadXMLDoc(this)"> Попробуйте </button>
Пример 2
<script> function loadXMLDoc(but,url) { but.disabled = true; var XHR = ("onload" in new XMLHttpRequest()) ? XMLHttpRequest : XDomainRequest; var xhr = new XHR(); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { document.getElementById("p1").innerHTML=xhr.getAllResponseHeaders(); } } xhr.open("GET",url,true); xhr.send(); } </script> <p id="p1">Функция getAllResponseHeaders() возвращает заголовочную информацию ресурса, наподобие длины, типа сервера, типа содержимого, последнего изменения и т.д. </p> <button type="button" onclick="loadXMLDoc(this,'xhr/xmlhttp_info.txt')"> Получить заголовочную информацию </button>
Пример 3
<script> function loadXMLDoc(but,url) { but.disabled = true; var XHR = ("onload" in new XMLHttpRequest()) ? XMLHttpRequest : XDomainRequest; var xhr = new XHR(); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { document.getElementById("p1").innerHTML = "Content-Type: " + xhr.getResponseHeader('Content-Type'); } } xhr.open("GET",url,true); xhr.send(); } </script> <p id="p1">Функция getResponseHeader() используется, чтобы получить информацию по конкретному заголовку для ресурса, наподобие длины, типа сервера, типа содержимого, даты и времени последней модификации и т.д. </p> <button type="button" onclick="loadXMLDoc(this,'xhr/xmlhttp_info.txt')"> Получить информацию по заголовку "Content-Type" </button>
Пример 4
<script> function showCustomer(str) { if (str=="") { document.getElementById("d1").innerHTML=""; return; } var XHR = ("onload" in new XMLHttpRequest()) ? XMLHttpRequest : XDomainRequest; var xhr = new XHR(); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { document.getElementById("d1").innerHTML = xhr.responseText; } } xhr.open("GET","xhr/ex4.php?q="+str,true); xhr.send(); } </script> <select onchange="showCustomer(this.value)"> <option value="">Изменить клиента:</option> <option value="PETROVI">Иван Петров</option> <option value="SIDOROVV">Василий Сидоров</option> <option value="BYKOVA">Андрей Быков</option> </select><br><br> <div id="d1"> Информация о клиенте будет показана здесь...</div>
Пример 5
<script> function loadXMLDoc(url) { var XHR = ("onload" in new XMLHttpRequest()) ? XMLHttpRequest : XDomainRequest; var xhr = new XHR(); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { var txt="<table border='1'><tr>" + "<th>Заголовок</th>" + "<th>Артист</th>"+ "</tr>"; var x = xhr.responseXML.documentElement.getElementsByTagName("CD"); for (i=0;i<x.length;i++) { txt=txt + "<tr>"; xx=x[i].getElementsByTagName("TITLE"); try { txt=txt + "<td>" + xx[0].firstChild.nodeValue + "</td>"; } catch (er) { txt=txt + "<td> </td>"; } xx=x[i].getElementsByTagName("ARTIST"); try { txt=txt + "<td>" + xx[0].firstChild.nodeValue + "</td>"; } catch (er) { txt=txt + "<td> </td>"; } txt=txt + "</tr>"; } txt=txt + "</table>"; document.getElementById('p1').innerHTML=txt; } } xhr.open("GET",url,true); xhr.send(); } </script> <div id="p1"><h3> Получение содержимого XML файла </h3> <button onclick="loadXMLDoc('xhr/cd_catalog.xml')"> Получить информацию о CD дисках </button> </div>
Пример 6
<script> function showHint(str) { if (str.length==0) { document.getElementById("p1").innerHTML=""; return; } var XHR = ("onload" in new XMLHttpRequest()) ? XMLHttpRequest : XDomainRequest; var xhr = new XHR(); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { document.getElementById("p1").innerHTML=xhr.responseText; } } xhr.open("GET","xhr/ex6.php?q="+encodeURIComponent(str),true); xhr.send(); } </script> <h3>Начните печатать имя в поле ввода ниже:</h3> Имя: <input type="text" id="txt1" onkeyup="showHint(this.value)" /> <p>Предложения: <span id="p1"></span></p>
Пример 7
<style> li p {margin: 0 0 8px 40px;} </style> <button onclick="loadPhones(this)"> Загрузить phones.json! </button> <ul id="list"></ul> <script> function loadPhones(but) { var xhr = new XMLHttpRequest(); xhr.open('GET', 'xhr/phones.json', true); xhr.onreadystatechange = function() { if (xhr.readyState != 4) return; but.parentNode.removeChild(but); if (xhr.status != 200) { alert(xhr.status + ': ' + xhr.statusText); } else { try { var phones = JSON.parse(xhr.responseText); } catch (e) { alert("Некорректный ответ " + e.message); } showPhones(phones); } } xhr.send(); but.innerHTML = 'Загружаю...'; but.disabled = true; } function showPhones(phones) { phones.forEach(function(phone) { var li = list.appendChild(document.createElement('li')); li.innerHTML = phone.name+'<p>'+phone.snippet+'</p>'; }); } </script>
Пример 8
<p>Современные браузеры, исключая IE9-, поддерживают встроенный объект FormData, который кодирует формы для отправки на сервер.</p> <form name="person"> <table> <tr><td style="text-align:right"> Имя: </td><td><input name="name" value="Никита"></td></tr> <tr><td style="text-align:right"> Фамилия: </td><td><input name="surname" value="Рябков"></td></tr> </table> </form> <button onclick="sentForma(this)"> Отправить на сервер </button> <div id="output"></div> <script> // создать объект для формы var formData = new FormData(document.forms.person); // добавить к пересылке ещё пару ключ - значение formData.append("Age", "33"); formData.append("Profession", "Програмист"); function sentForma (but) { var xhr = new XMLHttpRequest(); xhr.onload = function() { if (xhr.readyState == 4 && xhr.status == 200) { but.parentNode.removeChild(but); document.getElementById("output").innerHTML=xhr.responseText; } } xhr.open("POST", "xhr/ex8.php"); xhr.send(formData); // отослать } </script>
Пример 9
// POST-запросы var user = { name: "Tom", age: 23 }; var request = new XMLHttpRequest(); function reqReadyStateChange() { if (request.readyState == 4 && request.status == 200) document.getElementById("output").innerHTML= "На Ваш запрос отвечаю:<br>"+request.responseText; } var body = "name=" + user.name + "&age="+user.age; request.open("POST", "xhr/postdata.php"); request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); request.onreadystatechange = reqReadyStateChange; request.send(body);Предполагается, что данные отправляются скрипту на языке php postdata.php, который может иметь, например, следующее содержание:
<?php $name = "Не известно"; $age = "Не известно"; if(isset($_POST['name'])) $name = $_POST['name']; if (isset($_POST['age'])) $age = $_POST['age']; echo "Ваше имя: $name <br> Ваш возраст: $age"; ?>
Пример 10. Определить форму в html и использовать ее для отправки
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <div id="output"></div> <form name="user" action="xhr/postdata.php"> <input type="text" name="name" placeholder="Введите имя" /><br/> <input type="text" name="age" placeholder="Введите возраст" /><br/> <input type="submit" name="submit" value="Отправить" /> </form> <script> // получаем объект формы var form = document.forms.user; // прикрепляем обработчик кнопки form.submit.addEventListener("click", sendRequest); // обработчик нажатия function sendRequest(event){ event.preventDefault(); var formData = new FormData(form); var request = new XMLHttpRequest(); request.open("POST", form.action); request.onreadystatechange = function () { if (request.readyState == 4 && request.status == 200) document.getElementById("output").innerHTML=request.responseText; } request.send(formData); } </script> </body> </html>