XMLHttpRequest â bu JavaScript da HTTP soârovlar qilish imkonini beruvchi oârnatilgan brauzer obyekti.
Nomida âXMLâ soâzi boâlishiga qaramay, u nafaqat XML formatida, balki har qanday maâlumotlar bilan ishlashi mumkin. Biz fayllarni yuklash/yuklab olish, jarayonni kuzatish va boshqa koâp narsalarni qilishimiz mumkin.
Hozirda XMLHttpRequest ni bir oz eskirgan holda qoldiradigan boshqa, zamonaviyroq fetch metodi mavjud.
Zamonaviy veb-ishlanmada XMLHttpRequest uch sabab bilan ishlatiladi:
- Tarixiy sabablar: biz
XMLHttpRequestbilan mavjud scriptâlarni qoâllab-quvvatlashimiz kerak. - Biz eski brauzerlarni qoâllab-quvvatlashimiz va polyfillâlar ishlatishni xohlamaymiz (masalan, scriptâlarni kichik saqlash uchun).
- Bizga
fetchhali qila olmaydigan narsa kerak, masalan yuklash jarayonini kuzatish.
Bu tanish tuyuladimi? Agar ha boâlsa, XMLHttpRequest bilan davom eting. Aks holda, Fetch ga oâting.
Asoslar
XMLHttpRequest ikkita ishlash rejimiga ega: sinxron va asinxron.
Avval asinxronni koâraylik, chunki u koâpchilik hollarda ishlatiladi.
Soârov qilish uchun bizga 3 qadam kerak:
-
XMLHttpRequestyaratish:let xhr = new XMLHttpRequest();Konstruktor hech qanday argumentga ega emas.
-
Uni ishga tushirish, odatda
new XMLHttpRequestdan keyin darhol:xhr.open(method, URL, [async, user, password])Bu metod soârovning asosiy parametrlarini belgilaydi:
methodâ HTTP-metod. Odatda"GET"yoki"POST".URLâ soârov qilinadigan URL, string, URL obyekti boâlishi mumkin.asyncâ agar aniq ravishdafalsega oârnatilsa, soârov sinxron boâladi, buni biroz keyinroq koârib chiqamiz.user,passwordâ asosiy HTTP auth uchun login va parol (agar kerak boâlsa).
Diqqat qiling,
openchaqiruvi, nomiga qaramay, ulanishni ochmaydi. U faqat soârovni sozlaydi, lekin tarmoq faolligi faqatsendchaqiruvi bilan boshlanadi. -
Uni yuborish.
xhr.send([body])Bu metod ulanishni ochadi va soârovni serverga yuboradi. Ixtiyoriy
bodyparametri soârov tanasini oâz ichiga oladi.GETkabi baâzi soârov metodlari tanaga ega emas.POSTkabi baâzilari esa maâlumotlarni serverga yuborish uchunbodydan foydalanadi. Buning misollarini keyinroq koâramiz. -
Javob uchun
xhreventâlarini tinglash.Bu uchta event eng keng qoâllaniladi:
loadâ soârov tugallanganda (HTTP status 400 yoki 500 boâlsa ham), va javob toâliq yuklab olinganda.errorâ soârov qilinmagan boâlsa, masalan tarmoq ishlamay qolganda yoki notoâgâri URL.progressâ javob yuklanayotganda vaqti-vaqti bilan ishga tushadi, qancha yuklanganini xabar beradi.
xhr.onload = function() { alert(`Yuklandi: ${xhr.status} ${xhr.response}`); }; xhr.onerror = function() { // faqat so'rov umuman qilinmagan bo'lsa ishga tushadi alert(`Tarmoq Xatosi`); }; xhr.onprogress = function(event) { // vaqti-vaqti bilan ishga tushadi // event.loaded - necha bayt yuklab olingan // event.lengthComputable = agar server Content-Length header yuborgan bo'lsa true // event.total - umumiy baytlar soni (agar lengthComputable bo'lsa) alert(`${event.total} dan ${event.loaded} qabul qilindi`); };
Mana toâliq misol. Quyidagi kod serverdan /article/xmlhttprequest/example/load URLâini yuklaydi va jarayonni chop etadi:
// 1. Yangi XMLHttpRequest obyektini yaratish
let xhr = new XMLHttpRequest();
// 2. Uni sozlash: /article/.../load URL uchun GET-so'rov
xhr.open('GET', '/article/xmlhttprequest/example/load');
// 3. So'rovni tarmoq orqali yuborish
xhr.send();
// 4. Bu javob olingandan keyin chaqiriladi
xhr.onload = function() {
if (xhr.status != 200) { // javobning HTTP statusini tahlil qilish
alert(`Xato ${xhr.status}: ${xhr.statusText}`); // masalan 404: Not Found
} else { // natijani ko'rsatish
alert(`Tayyor, ${xhr.response.length} bayt olindi`); // response - server javobi
}
};
xhr.onprogress = function(event) {
if (event.lengthComputable) {
alert(`${event.total} dan ${event.loaded} bayt qabul qilindi`);
} else {
alert(`${event.loaded} bayt qabul qilindi`); // Content-Length yo'q
}
};
xhr.onerror = function() {
alert("So'rov muvaffaqiyatsiz");
};
Server javob bergandan keyin, biz natijani quyidagi xhr xususiyatlarida olishimiz mumkin:
status- HTTP status kodi (raqam):
200,404,403va boshqalar, HTTP boâlmagan muvaffaqiyatsizlik holatida0boâlishi mumkin. statusText- HTTP status xabari (string): odatda
200uchunOK,404uchunNot Found,403uchunForbiddenva boshqalar. response(eski scriptâlarresponseTextdan foydalanishi mumkin)- Server javob tanasi.
Shuningdek, tegishli xususiyat yordamida timeout belgilashimiz mumkin:
xhr.timeout = 10000; // ms da timeout, 10 soniya
Agar soârov berilgan vaqt ichida muvaffaqiyatli boâlmasa, u bekor qilinadi va timeout eventi ishga tushadi.
URL ga ?name=value kabi parametrlar qoâshish va toâgâri kodlashni taâminlash uchun URL obyektidan foydalanishimiz mumkin:
let url = new URL('https://google.com/search');
url.searchParams.set('q', 'test me!');
// 'q' parametri kodlangan
xhr.open('GET', url); // https://google.com/search?q=test+me%21
Javob Turi
Javob formatini belgilash uchun xhr.responseType xususiyatidan foydalanishimiz mumkin:
""(standart) â string sifatida olish,"text"â string sifatida olish,"arraybuffer"âArrayBuffersifatida olish (ikkilik maâlumotlar uchun, ArrayBuffer, binary arraylar bobiga qarang),"blob"âBlobsifatida olish (ikkilik maâlumotlar uchun, Blob bobiga qarang),"document"â XML hujjat (XPath va boshqa XML metodlaridan foydalanish mumkin) yoki HTML hujjat sifatida olish (olingan maâlumotlarning MIME turiga asoslanib),"json"â JSON sifatida olish (avtomatik parse qilinadi).
Masalan, javobni JSON sifatida olaylik:
let xhr = new XMLHttpRequest();
xhr.open('GET', '/article/xmlhttprequest/example/json');
xhr.responseType = 'json';
xhr.send();
// javob {"message": "Hello, world!"}
xhr.onload = function() {
let responseObj = xhr.response;
alert(responseObj.message); // Hello, world!
};
Eski scriptâlarda xhr.responseText va hatto xhr.responseXML xususiyatlarini ham topishingiz mumkin.
Ular tarixiy sabablarga koâra mavjud, string yoki XML hujjat olish uchun. Hozirda biz formatni xhr.responseType da oârnatish va yuqorida koârsatilganidek xhr.response olish kerak.
Tayyor holatlar
XMLHttpRequest jarayon davomida holatlar oârtasida oâzgaradi. Joriy holat xhr.readyState sifatida mavjud.
Spetsifikatsiyadagi barcha holatlar:
UNSENT = 0; // boshlang'ich holat
OPENED = 1; // open chaqirilgan
HEADERS_RECEIVED = 2; // javob header'lari olingan
LOADING = 3; // javob yuklanmoqda (ma'lumot paketi olingan)
DONE = 4; // so'rov tugallangan
XMLHttpRequest obyekti ularni 0 â 1 â 2 â 3 â ⦠â 3 â 4 tartibida bosib oâtadi. Holat 3 tarmoq orqali har safar maâlumot paketi olinganda takrorlanadi.
Biz ularni readystatechange event yordamida kuzatib borishimiz mumkin:
xhr.onreadystatechange = function() {
if (xhr.readyState == 3) {
// yuklanmoqda
}
if (xhr.readyState == 4) {
// so'rov tugallangan
}
};
Siz readystatechange listenerâlarini haqiqatan ham eski kodda topishingiz mumkin, u tarixiy sabablarga koâra mavjud, chunki load va boshqa eventâlar boâlmagan vaqt bor edi. Hozirda load/error/progress handlerâlari uni eskirgan holga keltiradi.
Soârovni toâxtatish
Biz soârovni istalgan vaqtda toâxtatishimiz mumkin. Buning uchun xhr.abort() chaqiruvi:
xhr.abort(); // so'rovni to'xtatish
Bu abort eventâini ishga tushiradi va xhr.status 0 boâladi.
Sinxron soârovlar
Agar open metodida uchinchi parametr async false ga oârnatilsa, soârov sinxron amalga oshiriladi.
Boshqacha qilib aytganda, JavaScript ijrosi send() da toâxtaydi va javob olinganidan keyin davom etadi. alert yoki prompt buyruqlari kabi.
Mana qayta yozilgan misol, open ning 3-parametri false:
let xhr = new XMLHttpRequest();
xhr.open('GET', '/article/xmlhttprequest/hello.txt', false);
try {
xhr.send();
if (xhr.status != 200) {
alert(`Xato ${xhr.status}: ${xhr.statusText}`);
} else {
alert(xhr.response);
}
} catch(err) { // onerror o'rniga
alert("So'rov muvaffaqiyatsiz");
}
Bu yaxshi koârinishi mumkin, lekin sinxron chaqiruvlar kamdan-kam ishlatiladi, chunki ular yuklash tugagunicha sahifadagi JavaScriptâni bloklaydi. Baâzi brauzerlarda scroll qilish imkonsiz boâladi. Agar sinxron chaqiruv juda koâp vaqt olsa, brauzer âosilib qolganâ veb-sahifani yopishni taklif qilishi mumkin.
XMLHttpRequest ning koâplab ilgâor imkoniyatlari, masalan boshqa domendan soârov qilish yoki timeout belgilash, sinxron soârovlar uchun mavjud emas. Shuningdek, koârib turganingizdek, progress koârsatkichi yoâq.
Bularning barchasiga koâra, sinxron soârovlar juda kam, deyarli hech qachon ishlatilmaydi. Biz ular haqida endi gapirmaymiz.
HTTP-headerâlar
XMLHttpRequest maxsus headerâlarni yuborish va javobdan headerâlarni oâqish imkonini beradi.
HTTP-headerâlar uchun 3 ta metod bor:
setRequestHeader(name, value)-
Berilgan
namevavaluebilan soârov headerâini oârnatadi.Masalan:
xhr.setRequestHeader('Content-Type', 'application/json');Headerâlar cheklovlariBir nechta headerâlar faqat brauzer tomonidan boshqariladi, masalan
ReferervaHost. Toâliq roâyxat spetsifikatsiyada.XMLHttpRequestga foydalanuvchi xavfsizligi va soârov toâgâriligi uchun ularni oâzgartirish ruxsat etilmagan.Headerâni oâchirib boâlmaydiXMLHttpRequestning yana bir xususiyati shundaki,setRequestHeaderni bekor qilib boâlmaydi.Header oârnatilgandan keyin, u oârnatilgan. Qoâshimcha chaqiruvlar headerâga maâlumot qoâshadi, uni qayta yozmaydi.
Masalan:
xhr.setRequestHeader('X-Auth', '123'); xhr.setRequestHeader('X-Auth', '456'); // header quyidagicha bo'ladi: // X-Auth: 123, 456 getResponseHeader(name)-
Berilgan
namebilan javob headerâini oladi (Set-CookievaSet-Cookie2bundan mustasno).Masalan:
xhr.getResponseHeader('Content-Type') getAllResponseHeaders()-
Set-CookievaSet-Cookie2bundan mustasno, barcha javob headerâlarini qaytaradi.Headerâlar bitta qator sifatida qaytariladi, masalan:
Cache-Control: max-age=31536000 Content-Length: 4260 Content-Type: image/png Date: Sat, 08 Sep 2012 16:53:16 GMTHeaderâlar orasidagi qator uzilishi har doim
"\r\n"(OS ga bogâliq emas), shuning uchun biz uni alohida headerâlarga osonlik bilan boâlishimiz mumkin. Nom va qiymat oârtasidagi ajratuvchi har doim ikki nuqta va boâshliq": ". Bu spetsifikatsiyada belgilangan.Shunday qilib, agar biz nom/qiymat juftligi bilan obyekt olishni istasak, biroz JS qoâshishimiz kerak.
Masalan (agar ikkita header bir xil nomga ega boâlsa, keyingisi avvalgisini qayta yozadi deb faraz qilib):
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 soârovi qilish uchun biz oârnatilgan FormData obyektidan foydalanishimiz mumkin.
Sintaksis:
let formData = new FormData([form]); // obyekt yaratadi, ixtiyoriy ravishda <form> dan to'ldiradi
formData.append(name, value); // maydon qo'shadi
Biz uni yaratamiz, ixtiyoriy ravishda formdan toâldiramiz, kerak boâlsa koâproq maydonlar append qilamiz, soângra:
xhr.open('POST', ...)âPOSTmetodidan foydalanish.xhr.send(formData)formani serverga yuborish.
Masalan:
<form name="person">
<input name="name" value="John">
<input name="surname" value="Smith">
</form>
<script>
// FormData ni formdan oldindan to'ldirish
let formData = new FormData(document.forms.person);
// yana bir maydon qo'shish
formData.append("middle", "Lee");
// uni yuborish
let xhr = new XMLHttpRequest();
xhr.open("POST", "/article/xmlhttprequest/post/user");
xhr.send(formData);
xhr.onload = () => alert(xhr.response);
</script>
Forma multipart/form-data kodlash bilan yuboriladi.
Yoki, agar biz JSON ni koâproq yoqtirsak, JSON.stringify qilib, string sifatida yuboramiz.
Faqat Content-Type: application/json headerâini oârnatishni unutmang, koâplab server-side frameworkâlari JSON ni u bilan avtomatik dekodlaydi:
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) metodi juda omnivor (hamma yeydi). U Blob va BufferSource obyektlari kabilarni qoâshganda deyarli har qanday body ni yuborishi mumkin.
Yuklash jarayoni
progress eventi faqat yuklab olish bosqichida ishga tushadi.
Yaâni: agar biz biror narsani POST qilsak, XMLHttpRequest avval bizning maâlumotlarimizni (soârov tanasi) yuklaydi, soângra javobni yuklab oladi.
Agar biz katta narsani yuklayotgan boâlsak, yuklash jarayonini kuzatish ancha qiziq. Lekin xhr.onprogress bu yerda yordam bermaydi.
Faqat yuklash eventâlarini kuzatish uchun metodlarsiz boshqa obyekt mavjud: xhr.upload.
U xhr ga oâxshash eventâlar yaratadi, lekin xhr.upload ularni faqat yuklashda ishga tushiradi:
loadstartâ yuklash boshlandi.progressâ yuklash davomida vaqti-vaqti bilan ishga tushadi.abortâ yuklash toâxtatildi.errorâ HTTP boâlmagan xato.loadâ yuklash muvaffaqiyatli tugallandi.timeoutâ yuklash vaqti tugadi (timeoutxususiyati oârnatilgan boâlsa).loadendâ yuklash muvaffaqiyat yoki xato bilan tugallandi.
Handlerâlar misoli:
xhr.upload.onprogress = function(event) {
alert(`${event.total} dan ${event.loaded} bayt yuklandi`);
};
xhr.upload.onload = function() {
alert(`Yuklash muvaffaqiyatli tugallandi.`);
};
xhr.upload.onerror = function() {
alert(`Yuklash paytida xato: ${xhr.status}`);
};
Mana haqiqiy hayotdagi misol: jarayon koârsatkichi bilan fayl yuklash:
<input type="file" onchange="upload(this.files[0])">
<script>
function upload(file) {
let xhr = new XMLHttpRequest();
// yuklash jarayonini kuzatish
xhr.upload.onprogress = function(event) {
console.log(`${event.total} dan ${event.loaded} yuklandi`);
};
// tugallanishni kuzatish: muvaffaqiyatli yoki yo'q
xhr.onloadend = function() {
if (xhr.status == 200) {
console.log("muvaffaqiyat");
} else {
console.log("xato " + this.status);
}
};
xhr.open("POST", "/article/xmlhttprequest/post/upload");
xhr.send(file);
}
</script>
Cross-origin soârovlar
XMLHttpRequest fetch bilan bir xil CORS siyosatini ishlatib, cross-origin soârovlar qilishi mumkin.
Xuddi fetch kabi, u sukut boâyicha boshqa origin ga cookie va HTTP-authorization yubormaydi. Ularni yoqish uchun xhr.withCredentials ni true ga oârnating:
let xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open('POST', 'http://anywhere.com/request');
...
Cross-origin headerâlar haqida batafsil maâlumot uchun Fetch: Cross-Origin So'rovlari bobiga qarang.
Xulosa
XMLHttpRequest bilan GET-soârovning odatiy kodi:
let xhr = new XMLHttpRequest();
xhr.open('GET', '/my/url');
xhr.send();
xhr.onload = function() {
if (xhr.status != 200) { // HTTP xatosi?
// xatoni boshqarish
alert( 'Xato: ' + xhr.status);
return;
}
// javobni xhr.response dan olish
};
xhr.onprogress = function(event) {
// jarayonni xabar qilish
alert(`${event.total} dan ${event.loaded} yuklandi`);
};
xhr.onerror = function() {
// HTTP bo'lmagan xatoni boshqarish (masalan, tarmoq ishlamaydi)
};
Aslida koâproq eventâlar bor, zamonaviy spetsifikatsiya ularni roâyxatlaydi (hayot sikli tartibida):
loadstartâ soârov boshlandi.progressâ javobning maâlumot paketi keldi, ayni paytdagi butun javob tanasiresponseda.abortâ soârovxhr.abort()chaqiruvi bilan bekor qilindi.errorâ ulanish xatosi yuz berdi, masalan notoâgâri domen nomi. 404 kabi HTTP-xatolari uchun sodir boâlmaydi.loadâ soârov muvaffaqiyatli tugallandi.timeoutâ soârov timeout tufayli bekor qilindi (faqat oârnatilgan boâlsa sodir boâladi).loadendâload,error,timeoutyokiabortdan keyin ishga tushadi.
error, abort, timeout va load eventâlari bir-birini istisno qiladi. Ulardan faqat bittasi sodir boâlishi mumkin.
Eng koâp ishlatiladigan eventâlar yuklash tugallandi (load), yuklash muvaffaqiyatsiz (error), yoki biz bitta loadend handler ishlatib, nima boâlganini koârish uchun soârov obyekti xhr xususiyatlarini tekshirishimiz mumkin.
Biz yana bir event ni koârdik: readystatechange. Tarixan, u ancha oldin, spetsifikatsiya barqarorlashishidan oldin paydo boâlgan. Hozirda uni ishlatish shart emas, biz uni yangi eventâlar bilan almashtirishimiz mumkin, lekin uni eski scriptâlarda tez-tez topish mumkin.
Agar biz maxsus ravishda yuklashni kuzatishimiz kerak boâlsa, xhr.upload obyektidagi bir xil eventâlarni tinglashimiz kerak.
Izohlar
<code>yorlig'ini ishlating, bir nechta satrlar uchun - ularni<pre>yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepenâ¦)