XMLHTTP (XMLHttpRequest, XHR) - API, доступне в скриптових мовах браузерів, таких як JavaScript. Використовує запити HTTP або HTTPS безпосередньо до веб сервера і завантажує дані відповіді сервера безпосередньо в викликає скрипт. [1] Інформація може передаватися в будь-якому текстовому форматі, наприклад, в XML, HTML або JSON. Дозволяє здійснювати HTTP-запити до сервера без перезавантаження сторінки.

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

Хоча в назві присутня абревіатура XML, технологія не накладає обмежень на формат переданих даних. Дані можна пересилати як у вигляді XML, так і в JSON, HTML або просто неструктурованим текстом. Розробник може самостійно створити формат для передачі даних. Однак потрібно враховувати, що при пересиланні використовується текстовий протокол HTTP і тому при використанні методу GET дані повинні передаватися у вигляді тексту (тобто бінарні дані слід кодувати, наприклад в base64). При використанні методу POST в кодуванні немає необхідності.


1. Історія

Вперше був розроблений компанією Microsoft, з'явившись в компоненті Outlook Web Access програмного продукту Microsoft Exchange Server 2000. Він був названий IXMLHTTPRequest. Пізніше, напрацювання були включені до складу MSXML 2.0 у вигляді об'єкта ActiveX, доступного через JScript, VBScript або інші скриптові мови, які підтримуються браузером. MSXML 2.0 був включений до складу браузера Internet Explorer 5.

Програмісти проекту Mozilla потім розробили сумісну версію, що називається nsIXMLHttpRequest в Mozilla 0.6. Доступ до компонента був реалізований через JavaScript-об'єкт, названий XMLHttpRequest. Однак, повної функціональності вдалося досягти тільки в Mozilla 1.0. Надалі підтримка XMLHttpRequest з'явилася в браузерах Safari 1.2, Opera 8.01 і в інших.

Остання офіційна специфікація - версія 1.0 (XMLHttpRequest Version 1.0 від 3 серпня 2010 року), яка має статус кандидата в рекомендації (Candidate Recommendation) і версія 2.0 (XMLHttpRequest Level 2 від 7 вересня 2010 року), що має статус чернетки. У другій версії вводяться обробники подій прогресу, підтримка крос-доменних запитів і робота з бінарними даними. [2]


2. Методи класу XMLHttpRequest

Метод Опис
abort () Скасовує поточний запит, видаляє всі заголовки, ставить текст відповіді сервера в null.
getAllResponseHeaders () Повертає повний список HTTP-заголовків у вигляді рядка. Заголовки розділяються знаками переносу (CR + LF).
Якщо прапор помилки дорівнює true, повертає порожній рядок.
Якщо статус 0 чи 1, викликає помилку INVALID_STATE_ERR.
getResponseHeader (headerName) Повертає значення зазначеного заголовка.
Якщо прапор помилки дорівнює true, повертає null.
Якщо заголовок не знайдений, повертає null.
Якщо статус 0 чи 1, викликає помилку INVALID_STATE_ERR.
open (method, URL, async, userName, password) Визначає метод, URL та інші опціональні параметри запиту;
параметр async визначає, чи відбувається робота в асинхронному режимі.
Останні два параметри необов'язкові.
send (content) Відправляє запит на сервер.
setRequestHeader (label, value) Додає HTTP-заголовок до запиту.
overrideMimeType (mimeType) Дозволяє вказати mime-type документа, якщо сервер його не передав або передав неправильно.
Увага: метод відсутній в Internet Explorer!

3. Властивості класу XMLHttpRequest

Властивість Тип Опис
onreadystatechange EventListener Обробник події, яка відбувається при кожній зміні стану об'єкта. Ім'я повинно бути записано в нижньому регістрі.
readyState unsigned short Поточний стан об'єкта (0 - не ініціалізований, 1 - відкритий, 2 - відправка даних, 3 - отримання даних і 4 - дані завантажені)
responseText DOMString Текст відповіді на запит.
Якщо стан не 3 або 4, повертає порожній рядок.
responseXML Document Текст відповіді на запит у вигляді XML, який потім може бути оброблений за допомогою DOM.
Якщо стан не 4, повертає null.
status unsigned short HTTP-статус у вигляді числа ( 404 - "Not Found", 200 - "OK" і т. д.)
statusText DOMString Статус у вигляді рядка ("Not Found", "OK" і т. д.).
Якщо статус не розпізнано, браузер користувача повинен викликати помилку INVALID_STATE_ERR.

4. Помилки, викликані класом XMLHttpRequest

Назва Код Опис
SECURITY_ERR 18 Викликається при спробі вчинити запит, заборонений налаштуваннями безпеки в браузері користувача.
NETWORK_ERR 101 Викликається при помилці мережі (під час синхронного запиту).
ABORT_ERR 102 Викликається при перериванні користувачем запиту (під час синхронного запиту).

5. Приклад використання

План роботи з об'єктом XMLHttpRequest можна представити таким чином:

  1. Створення примірника об'єкта XMLHttpRequest
  2. Відкриття з'єднання
  3. Установка обробника події (потрібно робити після відкриття і до відправки в IE)
  4. Відправлення запиту.

Створення примірника об'єкта XMLHttpRequest.

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

Виклик для ранніх версій Internet Explorer виглядає так [3] :

 var  req  =  new  ActiveXObject  (  "Microsoft.XMLHTTP"  )  ; 

В інших браузерах:

 var  req  =  new  XMLHttpRequest  (  )  ; 

Тобто, для забезпечення крос-браузерні коду, потрібно лише перевіряти наявність об'єктів window.XMLHttpRequest і window.ActiveXObject, і, в залежності від того, який є, той і застосовувати.

В якості універсального рішення пропонується використання такої функції:

 function  createRequestObject  (  )  {  if  (  typeof  XMLHttpRequest  ===  'Undefined'  )  {  XMLHttpRequest  =  function  (  )  {  try  {  return  new  ActiveXObject  (  "Msxml2.XMLHTTP.6.0"  )  ;  }  catch  (  e  )  {  }  try  {  return  new  ActiveXObject  (  "Msxml2.XMLHTTP.3.0"  )  ;  }  catch  (  e  )  {  }  try  {  return  new  ActiveXObject  (  "Msxml2.XMLHTTP"  )  ;  }  catch  (  e  )  {  }  try  {  return  new  ActiveXObject  (  "Microsoft.XMLHTTP"  )  ;  }  catch  (  e  )  {  }  throw  new  Error  (  "This browser does not support XMLHttpRequest."  )  ;  }  ;  }  return  new  XMLHttpRequest  (  )  ;  } 

Установка обробника подій, відкриття з'єднання і відправка запитів

Ці виклики виглядають так:

 req.  open  (  <  "GET"  |  "POST"  |  ...  >,  <  url  >  [  ,  <  asyncFlag  >  [  ,  <  user  >,  <  password  >  ]  ]  )  ;  req.  onreadystatechange  =  processReqChange  ; 

Де:

  • <"GET" | "POST" | ...> - метод запиту. Допускаються: DELETE, GET, HEAD, OPTIONS, POST, PUT.
  • - адресу запиту.
  • - прапор, який визначає, чи використовувати асинхронний запит. За замовчуванням, встановлений в true.
  • , - логін і пароль, відповідно. Вказуються при необхідності.

Після визначення всіх параметрів запиту його залишається тільки відправити. Робиться це методом send (). При відправці 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.  open  (  "GET"  ,  url  ,  true  )  ;  req.  onreadystatechange  =  processReqChange  ;  req.  send  (  null  )  ;  }  }  function  processReqChange  (  )  {  try  {  / / Важливо!  / / Тільки при стані "complete"  if  (  req.  readyState  ==  4  )  {  / / Для статусу "OK"  if  (  req.  status  ==  200  )  {  / / Обробка відповіді  }  else  {  alert  (  "Не вдалося отримати дані:  \ N  "  +  req.  statusText  )  ;  }  }  }  catch  (  e  )  {  / / Alert ('Помилка:' + e.description);  / / В зв'язку з багом XMLHttpRequest в Firefox доводиться відловлювати помилку  / / Bugzilla Bug 238559 XMLHttpRequest needs a way to report networking errors  / / Https://bugzilla.mozilla.org/show_bug.cgi?id=238559  }  } 

6. Відомі проблеми

6.1. Проблема з Кешування в Microsoft Internet Explorer

Internet Explorer кешує GET-запити. Ті автори, які не знайомі з Кешування HTTP, очікують, що GET-запити не кешируючого, або що кеш може бути обійдений, як у випадку натиснення кнопки поновлення. У деяких ситуаціях уникнення кешування дійсно є помилкою. Одним з рішень є використання методу POST, який ніколи не кешируючого; однак він призначений для інших операцій. Іншим рішенням є використання методу запиту GET, що включає унікальну рядок запиту з кожним викликом, як показано на прикладі нижче.

 req.  open  (  "GET"  ,  "Xmlprovider.php? Hash ="  +  Math  .  random  (  )  )  ; 

Слід пам'ятати, що такий спосіб сильно забиває кеш. Краще скористатися установкою заголовка Expires на минулу дату у вашому скрипті, який генерує вміст XML. В PHP це буде так:

 header  (  "Cache-Control: no-store, no-cache, must-revalidate"  )  ;  header  (  "Expires:"  .  date  (  "R"  )  )  ;  header  (  "Expires: -1"  ,  false  )  ; 

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

 response.  setHeader  (  "Pragma"  ,  "No-cache"  )  ;  response.  setHeader  (  "Cache-Control"  ,  "Must-revalidate"  )  ;  response.  setHeader  (  "Cache-Control"  ,  "No-cache"  )  ;  response.  setHeader  (  "Cache-Control"  ,  "No-store"  )  ;  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  )  ; 

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