XMLHttpRequest â ÑÑо вÑÑÑоеннÑй в бÑаÑÐ·ÐµÑ Ð¾Ð±ÑекÑ, коÑоÑÑй даÑÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑÑ Ð´ÐµÐ»Ð°ÑÑ HTTP-запÑоÑÑ Ðº ÑеÑвеÑÑ Ð±ÐµÐ· пеÑезагÑÑзки ÑÑÑаниÑÑ.
ÐеÑмоÑÑÑ Ð½Ð° налиÑие Ñлова «XML» в названии, XMLHttpRequest Ð¼Ð¾Ð¶ÐµÑ ÑабоÑаÑÑ Ñ Ð»ÑбÑми даннÑми, а не ÑолÑко Ñ XML. ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ загÑÑжаÑÑ/ÑкаÑиваÑÑ ÑайлÑ, оÑÑлеживаÑÑ Ð¿ÑогÑеÑÑ Ð¸ многое дÑÑгое.
Ðа ÑегоднÑÑний Ð´ÐµÐ½Ñ Ð½Ðµ обÑзаÑелÑно иÑполÑзоваÑÑ XMLHttpRequest, Ñак как ÑÑÑеÑÑвÑÐµÑ Ð´ÑÑгой, более ÑовÑеменнÑй меÑод fetch.
Ð ÑовÑеменной веб-ÑазÑабоÑке XMLHttpRequest иÑполÑзÑеÑÑÑ Ð¿Ð¾ ÑÑÑм пÑиÑинам:
- Ðо иÑÑоÑиÑеÑким пÑиÑинам: ÑÑÑеÑÑвÑÐµÑ Ð¼Ð½Ð¾Ð³Ð¾ кода, иÑполÑзÑÑÑего
XMLHttpRequest, коÑоÑÑй нÑжно поддеÑживаÑÑ. - ÐÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ÑÑÑ Ð¿Ð¾Ð´Ð´ÐµÑживаÑÑ ÑÑаÑÑе бÑаÑзеÑÑ Ð¸ нежелание иÑполÑзоваÑÑ Ð¿Ð¾Ð»Ð¸ÑÐ¸Ð»Ñ (напÑимеÑ, ÑÑÐ¾Ð±Ñ ÑменÑÑиÑÑ ÐºÐ¾Ð»Ð¸ÑеÑÑво кода).
- ÐоÑÑебноÑÑÑ Ð² ÑÑнкÑионалÑноÑÑи, коÑоÑÑÑ
fetchпока ÑÑо не Ð¼Ð¾Ð¶ÐµÑ Ð¿ÑедоÑÑавиÑÑ, к пÑимеÑÑ, оÑÑлеживание пÑогÑеÑÑа оÑпÑавки на ÑеÑвеÑ.
ЧÑо-Ñо из ÑÑого ÑпиÑка звÑÑÐ¸Ñ Ð·Ð½Ð°ÐºÐ¾Ð¼Ð¾? ÐÑли да, Ñогда впеÑÑд, пÑиÑÑного знакомÑÑва Ñ XMLHttpRequest. ÐÑли же неÑ, возможно, Ð¸Ð¼ÐµÐµÑ ÑмÑÑл изÑÑаÑÑ ÑÑÐ°Ð·Ñ Fetch.
ÐÑновÑ
XMLHttpRequest Ð¸Ð¼ÐµÐµÑ Ð´Ð²Ð° Ñежима ÑабоÑÑ: ÑÐ¸Ð½Ñ ÑоннÑй и аÑÐ¸Ð½Ñ ÑоннÑй.
СнаÑала ÑаÑÑмоÑÑим аÑÐ¸Ð½Ñ ÑоннÑй, Ñак как в болÑÑинÑÑве ÑлÑÑаев иÑполÑзÑеÑÑÑ Ð¸Ð¼ÐµÐ½Ð½Ð¾ он.
ЧÑÐ¾Ð±Ñ ÑделаÑÑ Ð·Ð°Ð¿ÑоÑ, нам нÑжно вÑполниÑÑ ÑÑи Ñага:
-
СоздаÑÑ
XMLHttpRequest.let xhr = new XMLHttpRequest(); // Ñ ÐºÐ¾Ð½ÑÑÑÑкÑоÑа Ð½ÐµÑ Ð°ÑгÑменÑовÐонÑÑÑÑкÑÐ¾Ñ Ð½Ðµ Ð¸Ð¼ÐµÐµÑ Ð°ÑгÑменÑов.
-
ÐниÑиализиÑоваÑÑ ÐµÐ³Ð¾.
xhr.open(method, URL, [async, user, password])ÐÑÐ¾Ñ Ð¼ÐµÑод обÑÑно вÑзÑваеÑÑÑ ÑÑÐ°Ð·Ñ Ð¿Ð¾Ñле
new XMLHttpRequest. Рнего пеÑедаÑÑÑÑ Ð¾ÑновнÑе паÑамеÑÑÑ Ð·Ð°Ð¿ÑоÑа:methodâ HTTP-меÑод. ÐбÑÑно ÑÑо"GET"или"POST".URLâ URL, кÑда оÑпÑавлÑеÑÑÑ Ð·Ð°Ð¿ÑоÑ: ÑÑÑока, Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¸ обÑÐµÐºÑ URL.asyncâ еÑли ÑказаÑÑfalse, Ñогда запÑÐ¾Ñ Ð±ÑÐ´ÐµÑ Ð²Ñполнен ÑÐ¸Ð½Ñ Ñонно, ÑÑо Ð¼Ñ ÑаÑÑмоÑÑим ÑÑÑÑ Ð¿Ð¾Ð·Ð¶Ðµ.user,passwordâ логин и паÑÐ¾Ð»Ñ Ð´Ð»Ñ Ð±Ð°Ð·Ð¾Ð²Ð¾Ð¹ HTTP-авÑоÑизаÑии (еÑли ÑÑебÑеÑÑÑ).
ÐамеÑим, ÑÑо вÑзов
open, вопÑеки ÑÐ²Ð¾ÐµÐ¼Ñ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ, не оÑкÑÑÐ²Ð°ÐµÑ Ñоединение. Ðн лиÑÑ ÐºÐ¾Ð½ÑигÑÑиÑÑÐµÑ Ð·Ð°Ð¿ÑоÑ, но непоÑÑедÑÑвенно оÑÑÑлаеÑÑÑ Ð·Ð°Ð¿ÑÐ¾Ñ ÑолÑко лиÑÑ Ð¿Ð¾Ñле вÑзоваsend. -
ÐоÑлаÑÑ Ð·Ð°Ð¿ÑоÑ.
xhr.send([body])ÐÑÐ¾Ñ Ð¼ÐµÑод ÑÑÑÐ°Ð½Ð°Ð²Ð»Ð¸Ð²Ð°ÐµÑ Ñоединение и оÑÑÑÐ»Ð°ÐµÑ Ð·Ð°Ð¿ÑÐ¾Ñ Ðº ÑеÑвеÑÑ. ÐеобÑзаÑелÑнÑй паÑамеÑÑ
bodyÑодеÑÐ¶Ð¸Ñ Ñело запÑоÑа.ÐекоÑоÑÑе ÑÐ¸Ð¿Ñ Ð·Ð°Ð¿ÑоÑов, Ñакие как
GET, не имеÑÑ Ñела. РнекоÑоÑÑе, как, напÑимеÑ,POST, иÑполÑзÑÑÑbody, ÑÑÐ¾Ð±Ñ Ð¾ÑпÑавлÑÑÑ Ð´Ð°Ð½Ð½Ñе на ÑеÑвеÑ. ÐÑ Ð¿Ð¾Ð·Ð¶Ðµ Ñвидим пÑимеÑÑ. -
СлÑÑаÑÑ ÑобÑÑÐ¸Ñ Ð½Ð°
xhr, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð»ÑÑиÑÑ Ð¾ÑвеÑ.ТÑи наиболее иÑполÑзÑемÑÑ ÑобÑÑиÑ:
loadâ пÑоиÑÑ Ð¾Ð´Ð¸Ñ, когда полÑÑен какой-либо оÑвеÑ, вклÑÑÐ°Ñ Ð¾ÑвеÑÑ Ñ HTTP-оÑибкой, напÑÐ¸Ð¼ÐµÑ 404.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 - колиÑеÑÑво Ð±Ð°Ð¹Ñ Ð²Ñего (ÑолÑко еÑли lengthComputable Ñавно true) 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-ÑÑаÑÑÑ Ð¾ÑвеÑа, еÑли ÑÑаÑÑÑ Ð½Ðµ 200, Ñо пÑоизоÑла оÑибка
alert(`ÐÑибка ${xhr.status}: ${xhr.statusText}`); // ÐапÑимеÑ, 404: Not Found
} else { // еÑли вÑÑ Ð¿ÑоÑло гладко, вÑводим ÑезÑлÑÑаÑ
alert(`ÐоÑово, полÑÑили ${xhr.response.length} байÑ`); // 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-меÑодÑ),"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 можно ÑказаÑÑ, ÑÑо ÑобÑÑие readystatechange «моÑалÑно ÑÑÑаÑело».
ÐÑмена запÑоÑа
ÐÑли Ð¼Ñ Ð¿ÐµÑедÑмали делаÑÑ Ð·Ð°Ð¿ÑоÑ, можно оÑмениÑÑ ÐµÐ³Ð¾ вÑзовом xhr.abort():
xhr.abort(); // завеÑÑиÑÑ Ð·Ð°Ð¿ÑоÑ
ÐÑи ÑÑом генеÑиÑÑеÑÑÑ ÑобÑÑие abort, а xhr.status ÑÑÑанавливаеÑÑÑ Ð² 0.
Ð¡Ð¸Ð½Ñ ÑоннÑе запÑоÑÑ
ÐÑли в меÑоде open ÑÑеÑий паÑамеÑÑ async ÑÑÑановлен на false, запÑÐ¾Ñ Ð²ÑполнÑеÑÑÑ ÑинÑ
Ñонно.
ÐÑÑгими Ñловами, вÑполнение JavaScript оÑÑанавливаеÑÑÑ Ð½Ð° send() и возобновлÑеÑÑÑ Ð¿Ð¾Ñле полÑÑÐµÐ½Ð¸Ñ Ð¾ÑвеÑа. Так ведÑÑ ÑебÑ, напÑимеÑ, ÑÑнкÑии alert или prompt.
ÐÐ¾Ñ Ð¿ÐµÑепиÑаннÑй пÑÐ¸Ð¼ÐµÑ Ñ Ð¿Ð°ÑамеÑÑом async, ÑавнÑм false:
let xhr = new XMLHttpRequest();
xhr.open('GET', '/article/xmlhttprequest/hello.txt', false);
try {
xhr.send();
if (xhr.status != 200) {
alert(`ÐÑибка ${xhr.status}: ${xhr.statusText}`);
} else {
alert(xhr.response);
}
} catch(err) { // Ð´Ð»Ñ Ð¾Ñлова оÑибок иÑполÑзÑем конÑÑÑÑкÑÐ¸Ñ try...catch вмеÑÑо onerror
alert("ÐапÑÐ¾Ñ Ð½Ðµ ÑдалÑÑ");
}
ÐÑглÑдиÑ, Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ, и Ð½ÐµÐ¿Ð»Ð¾Ñ Ð¾, но ÑÐ¸Ð½Ñ ÑоннÑе запÑоÑÑ Ð¸ÑполÑзÑÑÑÑÑ Ñедко, Ñак как они блокиÑÑÑÑ Ð²Ñполнение JavaScript до ÑÐµÑ Ð¿Ð¾Ñ, пока загÑÑзка не завеÑÑена. РнекоÑоÑÑÑ Ð±ÑаÑзеÑÐ°Ñ Ð½ÐµÐ»ÑÐ·Ñ Ð¿ÑокÑÑÑиваÑÑ ÑÑÑаниÑÑ, пока идÑÑ ÑÐ¸Ð½Ñ ÑоннÑй запÑоÑ. ÐÑ Ð° еÑли же ÑÐ¸Ð½Ñ ÑоннÑй запÑÐ¾Ñ Ð¿Ð¾ какой-Ñо пÑиÑине вÑполнÑеÑÑÑ ÑлиÑком долго, бÑаÑÐ·ÐµÑ Ð¿ÑÐµÐ´Ð»Ð¾Ð¶Ð¸Ñ Ð·Ð°ÐºÑÑÑÑ Â«Ð·Ð°Ð²Ð¸ÑÑÑÑ» ÑÑÑаниÑÑ.
Ðногие пÑодвинÑÑÑе возможноÑÑи XMLHttpRequest, Ñакие как вÑполнение запÑоÑа на дÑÑгой домен или ÑÑÑановка ÑаймаÑÑа, недоÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ ÑинÑ
ÑоннÑÑ
запÑоÑов. Также, как Ð²Ñ Ð¼Ð¾Ð³Ð»Ð¸ замеÑиÑÑ, ни о какой индикаÑии пÑогÑеÑÑа ÑеÑÑ ÑÑÑ Ð½Ðµ идÑÑ.
Ðз-за вÑего ÑÑого ÑÐ¸Ð½Ñ ÑоннÑе запÑоÑÑ Ð¸ÑполÑзÑÑÑ Ð¾ÑÐµÐ½Ñ Ñедко. ÐÑ Ð±Ð¾Ð»ÐµÐµ не бÑдем ÑаÑÑмаÑÑиваÑÑ Ð¸Ñ .
HTTP-заголовки
XMLHttpRequest ÑÐ¼ÐµÐµÑ ÐºÐ°Ðº ÑказÑваÑÑ Ñвои заголовки в запÑоÑе, Ñак и ÑиÑаÑÑ Ð¿ÑиÑланнÑе в оÑвеÑ.
ÐÐ»Ñ ÑабоÑÑ Ñ HTTP-заголовками еÑÑÑ 3 меÑода:
setRequestHeader(name, value)-
УÑÑÐ°Ð½Ð°Ð²Ð»Ð¸Ð²Ð°ÐµÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾Ðº запÑоÑа Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼
nameи знаÑениемvalue.ÐапÑимеÑ:
xhr.setRequestHeader('Content-Type', 'application/json');ÐгÑаниÑÐµÐ½Ð¸Ñ Ð½Ð° заголовкиÐекоÑоÑÑе заголовки ÑпÑавлÑÑÑÑÑ Ð¸ÑклÑÑиÑелÑно бÑаÑзеÑом, напÑимеÑ
RefererилиHost, а Ñакже ÑÑд дÑÑÐ³Ð¸Ñ . ÐолнÑй ÑпиÑок ÑÑÑ.XMLHttpRequestне ÑазÑеÑено изменÑÑÑ Ð¸Ñ Ñади безопаÑноÑÑи полÑзоваÑелей и Ð´Ð»Ñ Ð¾Ð±ÐµÑпеÑÐµÐ½Ð¸Ñ ÐºÐ¾ÑÑекÑноÑÑи HTTP-запÑоÑа.ÐоÑÑавленнÑй заголовок нелÑÐ·Ñ ÑнÑÑÑÐÑÑ Ð¾Ð´Ð½Ð¾Ð¹ оÑобенноÑÑÑÑ
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); // добавлÑем поле
ÐÑ ÑоздаÑм обÑекÑ, пÑи желании ÑказÑваем, из какой ÑоÑÐ¼Ñ form взÑÑÑ Ð´Ð°Ð½Ð½Ñе, заÑем, еÑли нÑжно, Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ð¼ÐµÑода append добавлÑем дополниÑелÑнÑе полÑ, поÑле Ñего:
xhr.open('POST', ...)â ÑоздаÑмPOST-запÑоÑ.xhr.send(formData)â оÑÑÑлаем ÑоÑÐ¼Ñ ÑеÑвеÑÑ.
ÐапÑимеÑ:
<form name="person">
<input name="name" value="ÐеÑÑ">
<input name="surname" value="ÐаÑеÑкин">
</form>
<script>
// заполним FormData даннÑми из ÑоÑмÑ
let formData = new FormData(document.forms.person);
// добавим еÑÑ Ð¾Ð´Ð½Ð¾ поле
formData.append("middle", "ÐвановиÑ");
// оÑпÑавим даннÑе
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: "ÐаÑÑ",
surname: "ÐеÑÑов"
});
xhr.open("POST", '/submit')
xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8');
xhr.send(json);
ÐеÑод .send(body) веÑÑма вÑеÑден. Ðн Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑпÑавиÑÑ Ð¿ÑакÑиÑеÑки ÑÑо Ñгодно в body, вклÑÑÐ°Ñ Ð¾Ð±ÑекÑÑ Ñипа Blob и BufferSource.
ÐÑогÑеÑÑ Ð¾ÑпÑавки
СобÑÑие progress ÑÑабаÑÑÐ²Ð°ÐµÑ ÑолÑко на ÑÑадии загÑÑзки оÑвеÑа Ñ ÑеÑвеÑа.
Рименно: еÑли Ð¼Ñ Ð¾ÑпÑавлÑем ÑÑо-Ñо ÑеÑез POST-запÑоÑ, XMLHttpRequest ÑпеÑва оÑпÑÐ°Ð²Ð¸Ñ Ð½Ð°Ñи даннÑе (Ñело запÑоÑа) на ÑеÑвеÑ, а поÑом загÑÑÐ·Ð¸Ñ Ð¾ÑÐ²ÐµÑ ÑеÑвеÑа. Ð ÑобÑÑие progress бÑÐ´ÐµÑ ÑÑабаÑÑваÑÑ ÑолÑко во вÑÐµÐ¼Ñ Ð·Ð°Ð³ÑÑзки оÑвеÑа.
ÐÑли Ð¼Ñ Ð¾ÑпÑавлÑем ÑÑо-Ñо болÑÑое, Ñо Ð½Ð°Ñ Ð³Ð¾Ñаздо болÑÑе инÑеÑеÑÑÐµÑ Ð¿ÑогÑеÑÑ Ð¾ÑпÑавки даннÑÑ
на ÑеÑвеÑ. Ðо xhr.onprogress ÑÑÑ Ð½Ðµ поможеÑ.
СÑÑеÑÑвÑÐµÑ Ð´ÑÑгой обÑекÑ, без меÑодов, ÑолÑко Ð´Ð»Ñ Ð¾ÑÑÐ»ÐµÐ¶Ð¸Ð²Ð°Ð½Ð¸Ñ ÑобÑÑий оÑпÑавки: xhr.upload.
Ðн генеÑиÑÑÐµÑ ÑобÑÑиÑ, поÑ
ожие на ÑобÑÑÐ¸Ñ xhr, но ÑолÑко во вÑÐµÐ¼Ñ Ð¾ÑпÑавки даннÑÑ
на ÑеÑвеÑ:
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-авÑоÑизаÑии. ЧÑÐ¾Ð±Ñ ÑÑо измениÑÑ, ÑÑÑановиÑе 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â пÑибÑла ÑаÑÑÑ Ð´Ð°Ð½Ð½ÑÑ Ð¾ÑвеÑа, Ñело оÑвеÑа полноÑÑÑÑ Ð½Ð° даннÑй Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð¼Ð¾Ð¶Ð½Ð¾ полÑÑиÑÑ Ð¸Ð· ÑвойÑÑваresponseText.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â¦)