XMLHttpRequest
XMLHttpRequest вЂ” API-запит вебклієнта (браузера) РґРѕ вебсервера Р·Р° протоколоР� HTTP Сѓ фоновоР�Сѓ режиР�С–, для Р�РѕРІ РїСЂРѕРіСЂР°Р�ування JavaScript, JScript, VBScript С– РїРѕРґС–Р±РЅРёС…. Використовується для СЃРёРЅС…СЂРѕРЅРЅРѕРіРѕ або асинхронного РѕР±Р�С–РЅСѓ інфорР�ацією РІ довільноР�Сѓ текстовоР�Сѓ форР�аті (наприклад, XML, JSON, HTML). Дозволяє здійснювати HTTP-запити РґРѕ віддаленого сервера без потреби перезавантажувати сторінку. Застосування XMLHttpRequest справляє враження В«Р�иттєвої» РІС–РґРїРѕРІС–РґС– сервера, Сѓ РїРѕСЂС–РІРЅСЏРЅРЅС– Р· класичниР�Рё Р�етодоР� перезавантаження всієї сторінки для оновлення представленої РЅР° РЅС–Р№ інфорР�ації.
XMLHttpRequest є невід'є�ною частиною технології AJAX і використовується багать�а сайта�и для створення дина�ічних вебзастосунків, що швидко реагують на запити користувача. Наприклад XMLHTTP використовується таки�и сайта�и як Gmail, Google Suggest, MSN Virtual Earth та інши�и. XMLHTTP працює лише з файла�и, розташовани�и на то�у ж до�ені, з якої завантажено сторінку. Як і у випадку JavaScript, це зроблено з �етою забезпечення безпеки користувача (як захист від атаки, що �ає назву «�іжсайтові сценарії», англ. cross-site scripting).
Історія
Вперше Р±СѓРІ реалізований РєРѕР�панією Microsoft, Р·'явившись РІ Internet Explorer 5.0 Сѓ вигляді РѕР±'єкта ActiveX, доступного через JavaScript, JScript, VBScript вЂ” скриптові Р�РѕРІРё, що підтриР�уються браузероР�. РџСЂРѕРіСЂР°Р�істи проекту Mozilla потіР� розробили СЃСѓР�С–СЃРЅСѓ версію, РїС–Рґ назвою XMLHttpRequest[1], РІ 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
Р’ Internet Explorer, якщо open() викликаний після установки onreadystatechange, Р�оже бути проблеР�Р° Р· повторниР� використанняР� цього XmlHttpRequest. Щоб використовувати наново XmlHttpRequest, спочатку викликайте Р�етод open(), Р° потіР� вЂ” призначайте onreadystatechange. Це потрібно тоР�Сѓ, що IE неявно очищає РѕР±'єкт XmlHttpRequest РІ Р�етоді open(), якщо Р№РѕРіРѕ стан В«completedВ».
Викликати abort() для перенаправлення запиту на іншій URL не потрібно, навіть якщо поточний запит ще не завершився.
Витоки па�'яті
Р’ Internet Explorer РѕР±'єкт XmlHttpRequest належить середовищу DOM/COM, Р° Javascript-функція вЂ” середовищу Javascript. Виклик req.onreadystatechange = function() { … } неявний РєСЂСѓРіРѕРІРёР№ Р·РІ'СЏР·РѕРє: req посилається РЅР° функцію через onreadystatechange, Р° функція, через область РІРёРґРёР�ості вЂ” бачить (посилається РЅР°) req.
Не�ожливість виявити і обірвати такий зв'язок в багатьох (до IE 6,7 редакцій червня 2007?) версіях Internet Explorer приводить до того, що XmlHttpRequest разо� з відповіддю сервера, функція-обробник, і все за�икання �іцно осідають в па�'яті до перезавантаження браузера. Щоб цього уникнути, ряд фрей�ворків (YUI, dojo…) взагалі не ставлять onreadystatechange, а нато�ість через setTimeout перевіряють його readyState кожні 10 �ілісекунд. Це розриває кругову зв'язку req <-> onreadystatechange, і витік па�'яті не загрожує навіть в найбільш глючних браузерах.
Об�еження безпеки
Кросс-до�енний XMLHttpRequest
Для РѕР±Р�еження XmlHttpRequest використовується філософія В«Same Origin PolicyВ» вЂ” «Правило РѕРґРЅРѕРіРѕ джерела». Р’РѕРЅРѕ дуже просте вЂ” кожен сайт працює РІ СЃРІРѕС—Р№ пісочниці. Запит Р�ожна робити тільки РЅР° адреси Р· тиР� же протоколоР�, РґРѕР�еноР�, портоР�, що С– поточна сторінка. Тобто, С–Р· сторінки РЅР° адресі http://site.com РЅРµ Р�ожна зробити XmlHttpRequest РЅР° адресу https://web.archive.org/web/20190617134849/http://www.site.com/, http://site.com:81[недоступне посилання Р· червня 2019] або https://web.archive.org/web/20030621190843/http://www.othersite.com/.
Це створює пробле�у, якщо хочеться узяти в�іст з іншого сайту. Як правило, в цьо�у випадку за�ість XmlHttpRequest використовуються інші засоби, наприклад, завантаження через дина�ічно створюваний тег <script>. Але, здебільшого, XmlHttpRequest є зручніши�.
РџСЂРѕРєСЃС–
Найпростіший СЃРїРѕСЃС–Р± обійти це РѕР±Р�еження вЂ” проксування. ПрипустиР�Рѕ, Р�Рё хочеР�Рѕ зробити запит Р· http://site.com [Архівовано 17 червня 2019 Сѓ Wayback Machine.] РЅР° https://web.archive.org/web/20150508130049/http://remote.com/get.html. Р—Р°Р�ість вказівки remote.com Сѓ Р�етоді open(), таР� ставиться URL РІРёРґСѓ http://site.com/proxy/remote.com/get.html[недоступне посилання Р· червня 2019], Р° сервер РЅР° site.com вже обробляє цей запит, СЏРє треба.
Якщо remote.com знаходиться на іншо�у сервері, то серверу site.com доведеться проксувати відвідувачеві як запит, так і відповідь. При цьо�у, зрозу�іло, site.com не отри�ає куки remote.com, то�у з цієї точки зору для користувача все безпечно.
Використання наддо�ену
Часто кросбраузерні запити вЂ” це СЃРїРѕСЃС–Р± обійти РѕР±Р�еження РІ 2 одночасних Р·'єднання РґРѕ РѕРґРЅРѕРіРѕ РґРѕР�ену-порту. РЎРїРѕСЃС–Р± використовувати РґРІР° СЂС–Р·РЅРёС… сервера РІ спілкуванні Р· відвідувачеР�. РљСЂРѕСЃ-РґРѕР�енні запити Р�С–Р¶ наддоР�енаР�Рё https://web.archive.org/web/20110102121034/http://a.site.com/, http://b.site.com[недоступне посилання Р· червня 2019] РЅР° http://site.com [Архівовано 17 червня 2019 Сѓ Wayback Machine.] допустиР�С–, через властивість document.domain, СЏРєРµ треба встановити РІ site.com
// на сторінці а.site.com
…
document.domain="site.com";
…
// все, тепер �ожу робити XmlHttpRequest на site.com
req.open("POST", "http://site.com/giveme.php")
�удь-які запити допусти�і �іж сайта�и, що знаходяться в довіреній (trusted) зоні Internet Explorer. Отже, внутрішній корпоративний портал �оже бути у всіх в цій зоні, і робити запити до будь-яких сайтів.
Ще один хитрий підхід називається XHRIframeProxy, і дозволяє робити XmlHttpRequest до будь-яких до�енів за допо�огою хитрого iframe-хака.
В плагінах Google Chrome
Пишучи аддон до браузера Google Chrome �ожна дозволити робити запити на довільні сервери, записавши їхні адреси в manifest.json
[2]
{
"name": "My extension",
...
"permissions": [
"http://www.google.com/"
],
...
}
При�ітки
- � Mozilla на�агалася зберегти �акси�альну су�існість із оригінало�, були вилучені лише пропрієтарні назви Microsoft та ActiveX
- � Архівована копія. Архів оригіналу за 8 лютого 2010. Процитовано 27 липня 2010.
{cite web}
: Обслуговування CS1: Сторінки з тексто� «archived copy» як значення пара�етру title (посилання) [Архівовано 2010-02-08 у Wayback Machine.]
Див. також
Посилання
- РћР±'єкт XMLHttpRequest [Архівовано 5 лютого 2012 Сѓ WebCite] вЂ” робочий нарис W3C
- яваскрипт.СѓРєСЂ/XMLHttpRequest [Архівовано 13 квітня 2021 Сѓ Wayback Machine.] вЂ” РїСЂРѕ XMLHttpRequest українською Р�РѕРІРѕСЋ.
- Apple Safari 1.2 [Архівовано 12 січня 2010 у Wayback Machine.]
- Microsoft IXMLHTTPRequest
- Mozilla XML Extras [Архівовано 30 листопада 2005 у Wayback Machine.]
- Mozilla XMLHttpRequest object HowTo [Архівовано 24 лютого 2006 у Wayback Machine.]
![]() |
Це незавершена стаття про Інтернет. Ви �ожете допо�огти проєкту, виправивши або дописавши її. |