XMLHttpRequest — API-запит вебклієнта (браузера) до вебсервера за протоколом HTTP у фоновому режимі, для мов програмування JavaScript, JScript, VBScript і подібних. Використовується для синхронного або асинхронного обміну інформацією в довільному текстовому форматі (наприклад, XML, JSON, HTML). Дозволяє здійснювати HTTP-запити до віддаленого сервера без потреби перезавантажувати сторінку. Застосування XMLHttpRequest справляє враження «миттєвої» відповіді сервера, у порівнянні з класичними методом перезавантаження всієї сторінки для оновлення представленої на ній інформації.

XMLHttpRequest є невід'ємною частиною технології AJAX і використовується багатьма сайтами для створення динамічних вебзастосунків, що швидко реагують на запити користувача. Наприклад XMLHTTP використовується такими сайтами як Gmail, Google Suggest, MSN Virtual Earth та іншими. XMLHTTP працює лише з файлами, розташованими на тому ж домені, з якої завантажено сторінку. Як і у випадку JavaScript, це зроблено з метою забезпечення безпеки користувача (як захист від атаки, що має назву «міжсайтові сценарії», ).

Історія Вперше був реалізований компанією Microsoft, з'явившись в Internet Explorer 5.0 у вигляді об'єкта ActiveX, доступного через JavaScript, JScript, VBScript — скриптові мови, що підтримуються браузером. Програмісти проекту Mozilla потім розробили сумісну версію, під назвою XMLHttpRequestMozilla намагалася зберегти максимальну сумісність із оригіналом, були вилучені лише пропрієтарні назви Microsoft та ActiveX, в Mozilla 1.0. Надалі ця можливість також була реалізована компаніями Apple починаючи з Safari 1.2, спорідненим браузером Konqueror, компанією Opera Software починаючи з Opera 8.01, і ймовірно іншими.

Оскільки оригінальний XMLHttpRequest в IE5 та IE6 є об'єктом ActiveX, його неможливо розширити, додавши нові властивості і методи, що іноді є незручним обмеженням. Це обмеження було знято в реалізації Mozilla — XMLHttpRequest є повноцінним об'єктом JavaScript. Починаючи з IE7 Microsoft теж почав дотримуватися рекомендованого w3c визначення запиту.

Методи класу XMLHttpRequest +МетодОпис abort() скасовує поточний запит getAllResponseHeaders() повертає повний список HTTP-заголовків у вигляді рядка getResponseHeader (headerName) повертає значення вказаного заголовка open (method, URL, async, userName, password) визначає метод, URL і інші необов'язкові параметри запиту; параметр async визначає, чи відбувається робота в асинхронному режимі send (content) відправляє запит на сервер setRequestHeader (label, value) додає HTTP-заголовок до запиту overrideMimeType (mimeType) дозволяє вказати MIME-тип документа, якщо сервер його не передав або передав неправильно. Увага: метод відсутній в Internet Explorer+

Властивості класу XMLHttpRequest +ВластивістьОпис onreadystatechange обробник події, яка відбувається при кожній зміні стану об'єкта (необхідний для асинхронного режиму) readyState повертає поточний стан об'єкта (0 — не ініціалізовано, 1 — відкрито, 2 — відправлення даних, 3 — отримання даних і 4 — дані завантажено) responseText текст відповіді на запит responseXML текст відповіді на запит в вигляді XML, котрий пізніше може бути розібраний методами DOM status повертає HTTP-стан у вигляді числа (404 — «Not Found, Не найдено», 200 — «OK» тощо) statusText повертає стан у вигляді рядка («Not Found», «OK» тощо)+

Приклад використання План роботи з об'єктом XMLHttpRequest можна представити так: Створення об'єкта XMLHttpRequest Встановлення для нього обробника події onreadystatechange Відкриття з'єднання з вказівкою типу запиту, URL і інших параметрів. Безпосередньо відправлення запиту.

Створення екземпляра класу XMLHttpRequest Перший пункт: створення екземпляра класу XMLHttpRequest. Конструкція створення об'єкта відрізняється в залежності від версії браузера: у IE 5 та IE 6 вона реалізована через ActiveXObject, а в решті браузерах (IE 7, Mozilla, Opera, Netscape і Safari) — як вбудований об'єкт типу XMLHttpRequest.

Отже, виклик для ранніх версій Internet Explorer: var req = new ActiveXObject("Microsoft.XMLHTTP"); У ранніх версіях Internet Explorer (до IE7) рекомендується використовувати: var req = new ActiveXObject("Msxml2.XMLHTTP"); і для решти: var req = new XMLHttpRequest();

Тобто, для забезпечення кросс-браузерності нашого коду, потрібно лише перевіряти наявність об'єктів window.XMLHttpRequest і window.ActiveXObject, і застосовувати присутній. Як універсальне рішення пропонується використання наступної функції: function createRequestObject() { if (window.XMLHttpRequest) { try { return new XMLHttpRequest(); } catch (e){} } else if (window.ActiveXObject) { try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e){} try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e){}

return null; }

Установлення обробника події Наступним кроком є створення обробника подій і відкриття з'єднання. Ці виклики виглядають просто і однаково: req.onreadystatechange = processReqChange; req.open(<"GET"|"POST"|...>, <url>, <asyncFlag>);

Відкриття з'єднання і відправлення Після визначення всіх параметрів запиту його залишається тільки відправити. Робиться це функцією send(). Якщо необхідно передати на сервер POST-дані, їх треба підставити як параметр для цієї функції. POST-дані повинні бути згорнуті в URL-закодований рядок (кодування UTF-8). Іншими словами цей рядок матиме вигляд, який ми звикли бачити в командному рядку браузера, при передачі даних командою GET. При відправленні запиту методом GET — для версії без ACTIVEX необхідно вказати параметр null, в решті випадків можна не указувати ніяких параметрів, але не буде помилкою, якщо для GET завжди буде вказаний параметр null: req.send(null);

Після цього починає працювати згаданий вище обробник подій. Він — фактично основна частина нашої програми. У обробнику зазвичай відбувається перехоплення всіх можливих кодів стану запиту і виклик відповідних дій, а також перехоплення можливих помилок. Власне, ось приклад частини коду з цими двома функціями: var req;

function loadXMLDoc(url) { req = null; if (window.XMLHttpRequest) { try { req = new XMLHttpRequest(); } catch (e){} } else if (window.ActiveXObject) { try { req = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e){ try { req = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e){}

if (req) { req.onreadystatechange = processReqChange; req.open("GET", url, true); req.send(null);

function processReqChange() { // Тільки в стані "complete" if (req.readyState == 4) { // для стану "OK" if (req.status == 200) { // Якщо 200 - робимо потрібні дії (404 - не знайдено) } else { alert("Не вдалось одержати дані:\n" + req.statusText);

Підсумковий код Отже, початковий код JavaScript-частини: var req; var reqTimeout;

function loadXMLDoc(url) { req = null; if (window.XMLHttpRequest) { try { req = new XMLHttpRequest(); } catch (e){} } else if (window.ActiveXObject) { try { req = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e){ try { req = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e){}

if (req) { req.onreadystatechange = processReqChange; req.open("GET", url, true); req.send(null); reqTimeout = setTimeout("req.abort();", 5000); } else { alert("Браузер не підтримує AJAX");

function processReqChange() { document.form1.state.value = stat(req.readyState);

if (req.readyState == 4) { clearTimeout(reqTimeout);

document.form1.statusnum.value = req.status; document.form1.status.value = req.statusText;

// only if "OK" if (req.status == 200) { document.form1.response.value=req.responseText; } else { alert("Не вдалося отримати дані:\n" + req.statusText);

function stat(n) { switch (n) { case 0: return "не ініціалізовано"; break;

case 1: return "Завантаження..."; break;

case 2: return "Завантажено"; break;

case 3: return "В процесі..."; break;

case 4: return "Виконано"; break;

default: return "Невідомий стан";

function requestdata(params) { loadXMLDoc('examples/httpreq.php'+params); }

Тепер — HTML-форма: <form name=form1> <table width=100% style="font-size: 100%"> <tr><td width=30% valign=top> Стан запиту <td width=70%> <input size=25 disabled type=text name=state value=""> <tr><td valign=top>Код стану <td><input disabled size=2 type=text name=statusnum value=""> <input disabled size=19 type=text name=status value=""> <tr><td valign=top>Дані від сервера <td><textarea rows=6 name=response></textarea> <tr><td>Рядок GET-запиту<td> <input type=text name=getparams value="?"> <input type=button onclick="requestdata(getparams.value);" value="GET"> </table> </form>

І наостанок, PHP файл: <?php header("Content-type: text/plain; charset=windows-1251"); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); header("Expires: -1");

echo "Hello world!\n\n";

if (isset($a)) { for ($i=1; $i < 10000; $i++)

echo 'Це тестовий рядок. '; if (($i % 1000) == 0) flush();

if (count($_GET) > 0) { echo "\n\nПередано GET'ом\n"; print_r($_GET); } ?>

Кодування Всі параметри GET/POST, що йдуть на сервер, окрім випадку multipart/form-data, кодуються по різному в різних браузерах. Зокрема, Firefox користується стандартним кодом URL, Opera вдається до кодування в UTF-8, IE7 передає кирилицю не кодуючи, як є. Тому треба бути уважним, інформація про спосіб кодування присутня в заголовках запиту. Наприклад, в PHP їх потрібно за потреби перекодувати функцією iconv. Єдино, можна бути певним, що латиниця не перекодовується в будь-якому випадку, і якщо є можливість залишитися в рамках латиниці, це позбавить програміста від додаткових клопотів.

Відповідь сервера браузер сприймає в тому кодуванні, яке вказане в заголовку відповіді Content-Type. Тобто, знову ж таки, в PHP, щоб браузер сприйняв відповідь в Windows-1251, потрібно послати заголовок типу: header(Content-Type: text/plain; charset=windows-1251); Або ж, це має зробити сервер.

Відомі проблеми Проблема з кешуванням в Microsoft Internet Explorer Internet Explorer кешує GET-запити. Ті автори, які незнайомі з кешуванням HTTP, сподіваються, що GET-запити не кешуються, або що кеш може бути обійдений, як у разі натиснення кнопки оновлення. У деяких ситуаціях уникнення кешування дійсно є помилкою. Одним з рішень є використання методу POST, який ніколи не кешується; проте він призначений для інших операцій. Іншим рішенням є використання методу запиту GET, що включає унікальний рядок запиту з кожним викликом, як показано на прикладі нижче. req.open("GET", "xmlprovider.php?hash=" + Math.random());

або установки заголовка Expires на минулу дату у вашому скрипті, який генерує вміст XML. У PHP це буде так: header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // disable IE caching header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header("Cache-Control: no-cache, must-revalidate"); header("Pragma: no-cache");

У сервлетах Java це буде так:

response.setHeader("Pragma", "no-cache"); response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); response.setDateHeader("Expires", 0);

Інакше можна примусити об'єкт XMLHttpRequest завжди витягати новий вміст, не використовуючи кеш.

req.open("GET", "xmlprovider.php"); req.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"); req.send(null);

Важливо відмітити, що всі ці методики повинні використовуватися у разі, коли кешування заважає. В основному ж краще отримати переваги в швидкості при кешуванні, можливо комбінуючи зі спеціально вказаними датами модифікації або іншими доречними заголовками на сервері так, щоб максимально використовувати кешування без отримання неправильних результатів.

Повторне використання об'єкта XmlHttpRequest