XMLHttpRequest â Ñе вбÑдований обâÑÐºÑ Ð±ÑаÑзеÑа, Ñкий дозволÑÑ Ð²Ð¸ÐºÐ¾Ð½ÑваÑи HTTP-запиÑи за Ð´Ð¾Ð¿Ð¾Ð¼Ð¾Ð³Ð¾Ñ JavaScript.
ÐопÑи Ñе, Ñо в Ð½Ð°Ð·Ð²Ñ Ñ Ñлово âXMLâ, вÑн може пÑаÑÑваÑи з бÑдÑ-Ñкими даними, а не лиÑе Ñ ÑоÑмаÑÑ XML. Ðи можемо заванÑажÑваÑи з/на ÑеÑÐ²ÐµÑ Ñайли, вÑдÑÑежÑваÑи пÑогÑÐµÑ Ñа багаÑо ÑнÑого.
ÐÐ¸Ð½Ñ ÑÑнÑÑ ÑнÑий, бÑлÑÑ ÑÑÑаÑний меÑод fetch, Ñкий, Ñ Ð±ÑлÑÑоÑÑÑ Ð²Ð¸Ð¿Ð°Ð´ÐºÑв, замÑнив XMLHttpRequest.
У ÑÑÑаÑнÑй веб-ÑозÑобÑÑ XMLHttpRequest викоÑиÑÑовÑÑÑÑÑÑ Ð· ÑÑÑоÑ
пÑиÑин:
- Ð ÑÑÑоÑиÑниÑ
пÑиÑин: нам поÑÑÑбно пÑдÑÑимÑваÑи наÑÐ²Ð½Ñ ÑкÑипÑи ÑÐºÑ Ð²Ð¸ÐºÐ¾ÑиÑÑовÑÑÑÑ
XMLHttpRequest. - Ðам поÑÑÑбно пÑдÑÑимÑваÑи ÑÑаÑÑ Ð±ÑаÑзеÑи Ñ Ð¼Ð¸ не Ñ Ð¾Ñемо викоÑиÑÑовÑваÑи полÑÑÑли (напÑиклад, Ñоб зменÑиÑи кÑлÑкÑÑÑÑ ÐºÐ¾Ð´Ñ).
- Ðам поÑÑÑбен ÑÑнкÑÑонал, Ñкий
fetchÑе не пÑдÑÑимÑÑ, напÑиклад вÑдÑÑежÑÐ²Ð°Ð½Ð½Ñ Ñ Ð¾Ð´Ñ Ð·Ð°Ð²Ð°Ð½ÑаженнÑ.
ЩоÑÑ Ð· ÑÑого звÑÑиÑÑ Ð·Ð½Ð°Ð¹Ð¾Ð¼Ð¾? ЯкÑо Ñак, Ñо пÑодовжÑйÑе знайомÑÑво з XMLHttpRequest. Ð ÑнÑÐ¾Ð¼Ñ Ð²Ð¸Ð¿Ð°Ð´ÐºÑ Ð¼Ð¾Ð¶Ð»Ð¸Ð²Ð¾ Ñ ÑÐµÐ½Ñ Ð¾Ð´ÑÐ°Ð·Ñ Ð¿ÐµÑейÑи до Fetch.
ÐÑнови
XMLHttpRequest Ð¼Ð°Ñ Ð´Ð²Ð° Ñежими ÑобоÑи: ÑÐ¸Ð½Ñ Ñонний Ñ Ð°ÑÐ¸Ð½Ñ Ñонний.
ÐавайÑе ÑпоÑаÑÐºÑ ÑозглÑнемо аÑÐ¸Ð½Ñ Ñонний, оÑкÑлÑки вÑн викоÑиÑÑовÑÑÑÑÑÑ Ð² бÑлÑÑоÑÑÑ Ð²Ð¸Ð¿Ð°Ð´ÐºÑв.
Щоб зÑобиÑи запиÑ, нам поÑÑÑбно виконаÑи 3 кÑоки:
-
СÑвоÑиÑи
XMLHttpRequest:let xhr = new XMLHttpRequest();ÐонÑÑÑÑкÑÐ¾Ñ Ð½Ðµ Ð¼Ð°Ñ Ð°ÑгÑменÑÑв.
-
ÐнÑÑÑалÑзÑваÑи його, зазвиÑай Ñе ÑоблÑÑÑ Ð²ÑдÑÐ°Ð·Ñ Ð¿ÑÑлÑ
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])Цей меÑод вÑдкÑÐ¸Ð²Ð°Ñ Ð·âÑÐ´Ð½Ð°Ð½Ð½Ñ Ñа надÑÐ¸Ð»Ð°Ñ Ð·Ð°Ð¿Ð¸Ñ Ð½Ð° ÑеÑвеÑ. ÐеобовâÑзковий паÑамеÑÑ
bodyмÑÑÑиÑÑ ÑÑло запиÑÑ.ÐеÑÐºÑ HTTP-меÑоди запиÑÑ, ÑÐ°ÐºÑ Ñк
GET, не маÑÑÑ ÑÑла. РдеÑÐºÑ Ð· Ð½Ð¸Ñ , напÑикладPOST, викоÑиÑÑовÑÑÑÑbodyÐ´Ð»Ñ Ð·Ð°Ð²Ð°Ð½ÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ Ð½Ð° ÑеÑвеÑ. Ðи побаÑимо пÑиклади ÑÑого пÑзнÑÑе. -
ÐÑоÑлÑÑ Ð¾Ð²ÑваÑи подÑÑ
xhr.ÐайÑаÑÑÑÑе викоÑиÑÑовÑÑÑÑÑÑ ÑÑ ÑÑи подÑÑ:
loadâ ÑпÑаÑÑовÑÑ ÐºÐ¾Ð»Ð¸ Ð·Ð°Ð¿Ð¸Ñ Ð·Ð°Ð²ÐµÑÑено (навÑÑÑ ÑкÑо ÑÑаÑÑÑ HTTP доÑÑвнÑÑ 400 або 500) Ñ Ð²ÑдповÑÐ´Ñ ÑеÑвеÑа повнÑÑÑÑ Ð·Ð°Ð²Ð°Ð½Ñажено.errorâ ÑпÑаÑÑовÑÑ ÐºÐ¾Ð»Ð¸ Ð·Ð°Ð¿Ð¸Ñ Ð½Ðµ може бÑÑи виконано, напÑиклад меÑежа не пÑаÑÑÑ Ð°Ð±Ð¾ задана не коÑекÑна URL-адÑеÑа.progressâ пеÑÑодиÑно ÑпÑаÑÑовÑÑ Ð¿Ñд ÑÐ°Ñ Ð·Ð°Ð²Ð°Ð½ÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð²ÑдповÑдÑ, Ñа повÑдомлÑÑ, ÑкÑлÑки байÑÑв бÑло заванÑажено.
xhr.onload = function() { alert(`ÐаванÑажено: ${xhr.status} ${xhr.response}`); }; xhr.onerror = function() { // ÑпÑаÑÑовÑÑ Ð»Ð¸Ñе в ÑÐ¾Ð¼Ñ Ð²Ð¸Ð¿Ð°Ð´ÐºÑ, ÑкÑо Ð·Ð°Ð¿Ð¸Ñ Ð²Ð·Ð°Ð³Ð°Ð»Ñ Ð½ÐµÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ð¾ зÑобиÑи alert(`ÐеÑежева помилка`); }; xhr.onprogress = function(event) { // ÑпÑаÑÑовÑÑ Ð¿ÐµÑÑодиÑно // event.loaded - ÑкÑлÑки байÑÑв бÑло заванÑажено // event.lengthComputable = true, ÑкÑо ÑеÑÐ²ÐµÑ Ð½Ð°Ð´ÑÑлав заголовок Content-Length // event.total - загалÑна кÑлÑкÑÑÑÑ Ð±Ð°Ð¹ÑÑв (ÑкÑо ÑеÑÐ²ÐµÑ Ð½Ð°Ð´ÑÑлав заголовок Content-Length) alert(`ÐÑÑимано ${event.loaded} з ${event.total}`); };
ÐÑÑ Ð¿Ð¾Ð²Ð½Ð¸Ð¹ пÑиклад. Ðаведений нижÑе код заванÑажÑÑ /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-ÑÑаÑÑÑ Ð²ÑдповÑдÑ
alert(`Ðомилка ${xhr.status}: ${xhr.statusText}`); // напÑиклад 404: Ðе знайдено
} else { // виводимо ÑезÑлÑÑаÑ
alert(`ÐÐ°Ð¿Ð¸Ñ Ð·Ð°Ð²ÐµÑÑено, оÑÑимано ${xhr.response.length} байÑ`); // влаÑÑивÑÑÑÑ `xhr.response` мÑÑÑиÑÑ Ð²ÑдповÑÐ´Ñ ÑеÑвеÑа
}
};
xhr.onprogress = function(event) {
if (event.lengthComputable) {
alert(`ÐÑÑимано ${event.loaded} Ñз ${event.total} байÑ`);
} else {
alert(`ÐÑÑимано ${event.loaded} байÑ`); // ÑкÑо ÑеÑÐ²ÐµÑ Ð½Ðµ надÑÑлав заголовок 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-адÑеÑи, напÑиклад ?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) або HTML-докÑÐ¼ÐµÐ½Ñ (на оÑÐ½Ð¾Ð²Ñ ÑÐ¸Ð¿Ñ MIME Ð´Ð»Ñ Ð¾ÑÑÐ¸Ð¼Ð°Ð½Ð¸Ñ Ð´Ð°Ð½Ð¸Ñ ),"json"â оÑÑимаÑи Ñк JSON (авÑомаÑиÑний аналÑз).
ÐапÑиклад, оÑÑимаймо вÑдповÑÐ´Ñ Ñ ÑоÑмаÑÑ JSON:
let xhr = new XMLHttpRequest();
xhr.open('GET', '/article/xmlhttprequest/example/json');
xhr.responseType = 'json';
xhr.send();
// ÑÑло вÑдповÑÐ´Ñ {"message": "ÐÑивÑÑ, ÑвÑÑ!"}
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.
СкаÑÑÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸ÑÑ
Ðи можемо ÑкаÑÑваÑи Ð·Ð°Ð¿Ð¸Ñ Ñ Ð±ÑдÑ-Ñкий ÑаÑ. Це можна зÑобиÑи за Ð´Ð¾Ð¿Ð¾Ð¼Ð¾Ð³Ð¾Ñ Ð¼ÐµÑода xhr.abort():
xhr.abort(); // ÑкаÑовÑÑмо запиÑ
Це ÑнÑÑÑÑÑ Ð¿Ð¾Ð´ÑÑ abort, а xhr.status ÑÑÐ°Ñ 0.
Ð¡Ð¸Ð½Ñ ÑÐ¾Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñи
ЯкÑо в меÑÐ¾Ð´Ñ open Ð´Ð»Ñ ÑÑеÑÑого паÑамеÑÑа async вÑÑановлено знаÑÐµÐ½Ð½Ñ false, Ñо Ð·Ð°Ð¿Ð¸Ñ Ð²Ð¸ÐºÐ¾Ð½ÑÑÑÑÑÑ ÑинÑ
Ñонно.
ÐнÑими Ñловами, Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ JavaScript пÑизÑпинÑÑÑÑÑÑ Ð² Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð²Ð¸ÐºÐ»Ð¸ÐºÑ Ð¼ÐµÑода send() Ñ Ð²ÑдновлÑÑÑÑÑÑ Ð¿ÑÑÐ»Ñ Ð¾ÑÑÐ¸Ð¼Ð°Ð½Ð½Ñ Ð²ÑдповÑдÑ. СÑ
ожим Ñином поводÑÑÑÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¸ alert Ñа prompt.
ÐÑÑ Ð¿ÐµÑепиÑаний пÑиклад, де 3-й паÑамеÑÑ open вÑÑановлено Ñ false:
let xhr = new XMLHttpRequest();
xhr.open('GET', '/article/xmlhttprequest/hello.txt', false);
try {
xhr.send();
if (xhr.status != 200) {
alert(`Error ${xhr.status}: ${xhr.statusText}`);
} else {
alert(xhr.response);
}
} catch(err) { // Ð´Ð»Ñ Ð¾Ð±Ñоки помилок викоÑиÑÑовÑÑмо try...catch замÑÑÑÑ Ð¿Ð¾Ð´ÑÑ onerror
alert("Ðе вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñи запиÑ");
}
Ðожливо Ñе Ñ Ð²Ð¸Ð³Ð»ÑÐ´Ð°Ñ Ð¿ÑийнÑÑно, але ÑÐ¸Ð½Ñ ÑÐ¾Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñи викоÑиÑÑовÑÑÑÑÑÑ ÑÑдко, оÑкÑлÑки вони блокÑÑÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ JavaScript на ÑÑоÑÑнÑÑ Ð´Ð¾ моменÑÑ Ð·Ð°Ð²ÐµÑÑÐµÐ½Ð½Ñ Ð·Ð°Ð²Ð°Ð½ÑаженнÑ. У деÑÐºÐ¸Ñ Ð±ÑаÑзеÑÐ°Ñ Ð¿ÑокÑÑÑÑÐ²Ð°Ð½Ð½Ñ ÑÑÐ°Ñ Ð½ÐµÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ð¸Ð¼. ЯкÑо ÑÐ¸Ð½Ñ Ñонний Ð·Ð°Ð¿Ð¸Ñ Ð·Ð°Ð¹Ð¼Ð°Ñ Ð·Ð°Ð½Ð°Ð´Ñо багаÑо ÑаÑÑ, бÑаÑÐ·ÐµÑ Ð¼Ð¾Ð¶Ðµ запÑопонÑваÑи закÑиÑи «виÑÑÑÑ» веб-ÑÑоÑÑнкÑ.
ÐагаÑо ÑозÑиÑениÑ
можливоÑÑей XMLHttpRequest, ÑакиÑ
Ñк Ð·Ð°Ð¿Ð¸Ñ Ð´Ð¾ ÑнÑого Ð´Ð¾Ð¼ÐµÐ½Ñ Ð°Ð±Ð¾ вÑÑÐ°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÑаÑÑ Ð¾ÑÑкÑÐ²Ð°Ð½Ð½Ñ Ð²ÑдповÑдÑ, недоÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ ÑинÑ
ÑонниÑ
запиÑÑв. ÐÑÑм Ñого, Ñк баÑиÑе, Ð½ÐµÐ¼Ð°Ñ ÑндикаÑоÑÑв пÑогÑеÑÑ.
ЧеÑез вÑе Ñе ÑÐ¸Ð½Ñ ÑÐ¾Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñи викоÑиÑÑовÑÑÑÑÑÑ Ð´Ñже ÑÑдко, майже нÑколи. Тож ми бÑлÑÑе не бÑдемо ÑÑ ÑозглÑдаÑи.
HTTP-заголовки
XMLHttpRequest дозволÑÑ Ñк надÑилаÑи влаÑÐ½Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¸, Ñак Ñ ÑиÑаÑи ÑÑ
з вÑдповÑдÑ.
ÐÑнÑÑ 3 меÑоди Ð´Ð»Ñ ÑобоÑи з HTTP-заголовками:
setRequestHeader(name, value)-
ÐÑÑановлÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾Ðº запиÑÑ Ñз заданими ÑмâÑм
nameÑа знаÑеннÑмvalue.ÐапÑиклад:
xhr.setRequestHeader('Content-Type', 'application/json');ÐÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÑвÐекÑлÑкома заголовками кеÑÑÑ Ð²Ð¸ÐºÐ»ÑÑно бÑаÑзеÑ, напÑиклад
RefererÑHost. Ðовний ÑÑ ÑпиÑок Ñ Ñ ÑпеÑиÑÑкаÑÑÑ.XMLHttpRequestне Ð¼Ð°Ñ Ð¿Ñава ÑÑ Ð·Ð¼ÑнÑваÑи з меÑÐ¾Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸ коÑиÑÑÑваÑа Ñа коÑекÑноÑÑÑ Ð·Ð°Ð¿Ð¸ÑÑ.ÐидалиÑи заголовок неможливоЩе одна оÑобливÑÑÑÑ
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]); // ÑÑвоÑÑÑмо обâÑкÑ, вÑн може бÑÑи заповнений з елеменÑа <form>
formData.append(name, value); // додаÑмо поле
Ðи ÑÑвоÑÑÑмо обâÑкÑ, за бажаннÑм додаÑмо Ð´Ð°Ð½Ñ Ð· ÑоÑми, Ñа ÑкÑо поÑÑÑбно, додаÑмо Ð¿Ð¾Ð»Ñ Ð·Ð° Ð´Ð¾Ð¿Ð¾Ð¼Ð¾Ð³Ð¾Ñ Ð¼ÐµÑода append, а поÑÑм:
xhr.open('POST', ...)â вÑÑановлÑÑмо меÑодPOST.xhr.send(formData)â Ñа надÑилаÑмо ÑоÑÐ¼Ñ Ð½Ð° ÑеÑвеÑ.
ÐапÑиклад:
<form name="person">
<input name="name" value="John">
<input name="surname" value="Smith">
</form>
<script>
// заповнÑÑмо FormData даними Ñз ÑоÑми
let formData = new FormData(document.forms.person);
// додаÑмо Ñе одне поле
formData.append("middle", "Lee");
// вÑдпÑавлÑÑмо запиÑ
let xhr = new XMLHttpRequest();
xhr.open("POST", "/article/xmlhttprequest/post/user");
xhr.send(formData);
xhr.onload = () => alert(xhr.response);
</script>
ФоÑма надÑилаÑÑÑÑÑ Ð· кодÑваннÑм multipart/form-data.
Ðбо, ÑкÑо нам бÑлÑÑе подобаÑÑÑÑÑ ÑоÑÐ¼Ð°Ñ JSON, ÑÐ¾Ð´Ñ Ð²Ð¸ÐºÐ¾ÑиÑÑовÑÑмо JSON.stringify Ñ Ð½Ð°Ð´ÑилаÑмо Ð´Ð°Ð½Ñ Ñк ÑÑдок.
ТÑлÑки не забÑдÑÑе вÑÑановиÑи заголовок Content-Type: application/json, багаÑо ÑеÑвеÑниÑ
ÑÑеймвоÑкÑв авÑомаÑиÑно декодÑÑÑÑ JSON за його наÑвноÑÑÑ:
let xhr = new XMLHttpRequest();
let json = JSON.stringify({
name: "John",
surname: "Smith"
});
xhr.open("POST", '/submit')
xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8');
xhr.send(json);
ÐеÑод .send(body) доÑиÑÑ Ð²ÑеÑдний. ÐÑн може надÑилаÑи майже бÑдÑ-ÑÐºÑ Ð´Ð°Ð½Ñ Ñ body, вклÑÑаÑÑи обâÑкÑи Blob Ñа BufferSource.
Ð¥Ñд заванÑаженнÑ
ÐодÑÑ progress ÑпÑаÑÑовÑÑ Ð»Ð¸Ñе на еÑÐ°Ð¿Ñ Ð·Ð°Ð²Ð°Ð½ÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ
з ÑеÑвеÑа.
ТобÑо ÑкÑо ми вÑдпÑавлÑÑмо POST запиÑ, Ñо XMLHttpRequest ÑпоÑаÑÐºÑ Ð·Ð°Ð²Ð°Ð½ÑажÑÑ Ð½Ð°ÑÑ Ð´Ð°Ð½Ñ (ÑÑло запиÑÑ) на ÑеÑвеÑ, а поÑÑм заванÑажÑÑ Ð²ÑдповÑÐ´Ñ Ð· ÑеÑвеÑа.
ЯкÑо ми заванÑажÑÑмо на ÑеÑÐ²ÐµÑ ÑоÑÑ Ð²ÐµÐ»Ð¸ÐºÐµ, Ñо ми, звиÑайно, бÑлÑÑе заÑÑÐºÐ°Ð²Ð»ÐµÐ½Ñ Ñ Ð²ÑдÑÑÐµÐ¶ÐµÐ½Ð½Ñ Ð¿ÑогÑеÑÑ Ð·Ð°Ð²Ð°Ð½ÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð½Ð° ÑеÑвеÑ. Ðле xhr.onprogress ÑÑÑ Ð½Ð°Ð¼ не допоможе.
ÐÑнÑÑ Ñе один обâÑÐºÑ Ð±ÐµÐ· меÑодÑв, пÑизнаÑений виклÑÑно Ð´Ð»Ñ Ð²ÑдÑÑÐµÐ¶ÐµÐ½Ð½Ñ Ð¿Ð¾Ð´Ñй заванÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð½Ð° ÑеÑвеÑ: xhr.upload.
ÐÑн генеÑÑÑ Ð¿Ð¾Ð´ÑÑ, подÑÐ±Ð½Ñ Ð´Ð¾ xhr, але xhr.upload ÑнÑÑÑÑÑ ÑÑ
виклÑÑно пÑд ÑÐ°Ñ Ð·Ð°Ð²Ð°Ð½ÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð½Ð° ÑеÑвеÑ:
loadstartâ ÑозпоÑаÑо заванÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð½Ð° ÑеÑвеÑ.progressâ ÑпÑаÑÑовÑÑ Ð¿ÐµÑÑодиÑно пÑд ÑÐ°Ñ Ð·Ð°Ð²Ð°Ð½ÑаженнÑ.abortâ заванÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð¿ÐµÑеÑвано.errorâ помилка не повâÑзана з HTTP.loadâ заванÑÐ°Ð¶ÐµÐ½Ð½Ñ ÑÑпÑÑно завеÑÑено.timeoutâ ÑÐ°Ñ Ð¾ÑÑкÑÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð²Ð°Ð½ÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð¼Ð¸Ð½Ñв (ÑкÑо вÑÑановлено влаÑÑивÑÑÑÑtimeout).loadendâ заванÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð·Ð°Ð²ÐµÑÑено (ÑÑпÑÑно або з помилкоÑ).
ÐÑиклад обÑобникÑв:
xhr.upload.onprogress = function(event) {
alert(`ÐаванÑажено на ÑеÑÐ²ÐµÑ ${event.loaded} Ñз ${event.total} байÑÑв`);
};
xhr.upload.onload = function() {
alert(`ÐаванÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð½Ð° ÑеÑÐ²ÐµÑ ÑÑпÑÑно завеÑÑено.`);
};
xhr.upload.onerror = function() {
alert(`СÑалаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° пÑд ÑÐ°Ñ Ð·Ð°Ð²Ð°Ð½ÑаженнÑ: ${xhr.status}`);
};
ÐÑÑ Ð¿Ñиклад Ñз ÑеалÑного жиÑÑÑ: заванÑÐ°Ð¶ÐµÐ½Ð½Ñ ÑÐ°Ð¹Ð»Ñ Ð½Ð° ÑеÑÐ²ÐµÑ Ð· ÑндикаÑÑÑÑ Ð¿ÑогÑеÑÑ:
<input type="file" onchange="upload(this.files[0])">
<script>
function upload(file) {
let xhr = new XMLHttpRequest();
// вÑдÑÑежÑÑмо Ñ
Ñд заванÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð½Ð° ÑеÑвеÑ
xhr.upload.onprogress = function(event) {
console.log(`ÐаванÑажено ${event.loaded} Ñз ${event.total}`);
};
// вÑдÑÑежÑÑмо завеÑÑеннÑ: ÑÑпÑÑне Ñи нÑ
xhr.onloadend = function() {
if (xhr.status == 200) {
console.log("ÑÑпÑÑно");
} else {
console.log("помилка " + this.status);
}
};
xhr.open("POST", "/article/xmlhttprequest/post/upload");
xhr.send(file);
}
</script>
ÐапиÑи на ÑнÑÑ Ð´Ð¶ÐµÑела
XMLHttpRequest може ÑобиÑи запиÑи ÑнÑÑ Ð´Ð¶ÐµÑела (ÑайÑи) викоÑиÑÑовÑÑÑи ÑÑ ÑÐ°Ð¼Ñ Ð¿Ð¾Ð»ÑÑÐ¸ÐºÑ CORS, Ñо й fetch.
Так Ñамо Ñк Ñ fetch, вÑн за замовÑÑваннÑм не надÑÐ¸Ð»Ð°Ñ ÑнÑим джеÑелам заголовки HTTP-авÑоÑизаÑÑÑ Ñа cookie. Щоб ÑвÑмкнÑÑи ÑÑ
, вÑÑановÑÑÑ Ð´Ð»Ñ 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(`ÐаванÑажено ${event.loaded} Ñз ${event.total}`);
};
xhr.onerror = function() {
// обÑоблÑÑмо Ð¿Ð¾Ð¼Ð¸Ð»ÐºÑ Ð½Ðµ повâÑÐ·Ð°Ð½Ñ Ð· HTTP (напÑиклад, ÑкÑо меÑежа не пÑаÑÑÑ)
};
ÐаÑпÑÐ°Ð²Ð´Ñ Ð¿Ð¾Ð´Ñй бÑлÑÑе, ÑÑÑаÑна ÑпеÑиÑÑкаÑÑÑ Ð¿ÐµÑелÑÑÑÑ ÑÑ (Ñ Ð¿Ð¾ÑÑÐ´ÐºÑ Ð¶Ð¸ÑÑÑвого ÑиклÑ):
loadstartâ Ð·Ð°Ð¿Ð¸Ñ Ð¿Ð¾ÑавÑÑ.progressâ надÑйÑов Ð¿Ð°ÐºÐµÑ Ð´Ð°Ð½Ð¸Ñ Ð²ÑдповÑдÑ, вÑе ÑÑло вÑдповÑÐ´Ñ Ð½Ð° даний Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð·Ð½Ð°Ñ Ð¾Ð´Ð¸ÑÑÑÑ Ñ Ð²Ð»Ð°ÑÑивоÑÑÑresponse.abortâ Ð·Ð°Ð¿Ð¸Ñ Ð±Ñло ÑкаÑовано викликомxhr.abort().errorâ ÑÑалаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° пÑдклÑÑеннÑ, напÑиклад непÑавилÑне доменне ÑмâÑ. Ðе ÑпÑаÑÑовÑÑ Ð´Ð»Ñ HTTP-помилок, ÑÐ°ÐºÐ¸Ñ Ñк 404.loadâ Ð·Ð°Ð¿Ð¸Ñ ÑÑпÑÑно завеÑÑено.timeoutâ Ð·Ð°Ð¿Ð¸Ñ Ð±Ñло ÑкаÑовано ÑеÑез Ñайм-аÑÑ (ÑÑлÑки ÑкÑо вÑн бÑв вÑÑановлений).loadendâ ÑпÑаÑÑовÑÑ Ð¿ÑÑÐ»Ñ Ð¿Ð¾Ð´Ñйload,error,timeoutабоabort.
ÐодÑÑ error, abort, timeout, Ñа load Ñ Ð²Ð·Ð°ÑмовиклÑÑними. Ðоже ÑпÑаÑÑваÑи лиÑе одна з ниÑ
.
ÐайÑаÑÑÑÑе викоÑиÑÑовÑÐ²Ð°Ð½Ñ Ð¿Ð¾Ð´ÑÑ â Ñе завеÑÑÐµÐ½Ð½Ñ Ð·Ð°Ð²Ð°Ð½ÑÐ°Ð¶ÐµÐ½Ð½Ñ (load), помилка заванÑÐ°Ð¶ÐµÐ½Ð½Ñ (error), або ми можемо викоÑиÑÑовÑваÑи один обÑобник loadend Ñ Ð¿ÐµÑевÑÑиÑи влаÑÑивоÑÑÑ Ð¾Ð±âÑкÑа запиÑÑ xhr, Ñоб побаÑиÑи, Ñо ÑÑалоÑÑ.
Також ми ÑозглÑнÑли ÑнÑÑ Ð¿Ð¾Ð´ÑÑ: readystatechange. Ðона зâÑвилаÑÑ Ð´Ñже давно, Ñе до Ñого, Ñк бÑло завеÑÑено ÑпеÑиÑÑкаÑÑÑ. ÐÐ¸Ð½Ñ Ð½ÐµÐ¼Ð° поÑÑеби ÑÑ Ð²Ð¸ÐºÐ¾ÑиÑÑовÑваÑи, адже Ñ Ð½Ð¾Ð²ÑÑÑ Ð¿Ð¾Ð´ÑÑ, але ÑÑ ÑаÑÑо можна зÑÑÑÑÑÑи в ÑÑаÑиÑ
ÑкÑипÑаÑ
.
ЯкÑо ж нам поÑÑÑбно вÑдÑÑежÑваÑи пÑогÑÐµÑ Ð·Ð°Ð²Ð°Ð½ÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð½Ð° ÑеÑвеÑ, ÑÐ¾Ð´Ñ Ð¼Ð¾Ð¶Ð½Ð° пÑоÑлÑÑ
овÑваÑи ÑÑ ÑÐ°Ð¼Ñ Ð¿Ð¾Ð´ÑÑ Ð½Ð° обâÑкÑÑ xhr.upload.
ÐоменÑаÑÑ
<code>, Ð´Ð»Ñ ÐºÑлÑÐºÐ¾Ñ ÑÑдкÑв â обгоÑнÑÑÑ ÑÑ Ñегом<pre>, Ð´Ð»Ñ Ð¿Ð¾Ð½Ð°Ð´ 10 ÑÑдкÑв â викоÑиÑÑовÑйÑе пÑÑоÑниÑÑ (plnkr, jsbin, codepenâ¦)