Mundarija (38)
- Bu darsda
- 1. Nega bu kerak?
- 2. fetch ning sozlamalar obyekti
- 2.1 Ikkinchi argument
- 2.2 Aks-sado: so'rovingizni ko'ring
- 3. JSON yuborish
- 3.1 Uch shart
- 3.2 Haqiqiy bron
- 3.3 Server rad etganda: 422
- 4. Content-Type ni unutsangiz
- 4.1 415: "bu turdagi ma'lumot qabul qilinmaydi"
- 4.2 stringify ni unutsangiz
- 5. Formadan yuborish: URLSearchParams va FormData
- 5.1 URLSearchParams — oddiy forma formati
- 5.2 FormData — fayllar bilan
- 5.3 FormData da Content-Type ni qo'lda yozmang
- 5.4 Server FormData ni qabul qilmasa
- 6. Content-Type qoidalari — bitta jadvalda
- 7. Boshqa metodlar: PUT, PATCH, DELETE
- 7.1 HTML forma qila olmaydigan ish
- 7.2 Metod nomini katta harfda yozing
- 7.3 GET ga tana berib bo'lmaydi
- 8. Bron formasi — haqiqiy serverga
- 9. Hujumchi nigohi
- 10. Ko'p uchraydigan xatolar
- 10.1 JSON uchun Content-Type yo'q
- 10.2 JSON.stringify yo'q
- 10.3 FormData ga qo'lda Content-Type
- 10.4 Formadagi sonlar — satr
- 10.5 Javobni tekshirmasdan "muvaffaqiyat" deyish
- 10.6 patch kichik harfda
- 11. Mashqlar
- 1-mashq (oson): Buyurtmani aks ettiring
- 2-mashq (o'rta): bronYubor funksiyasi
- 3-mashq (qiyin): Uch formatni solishtiring
- 12. Real ishda
- Xulosa
- Manbalar
fetch POST: JSON, FormData va URLSearchParams bilan ma'lumot yuborish
Qisqacha: Ma'lumot yuborish uchun
fetchga ikkinchi argument — sozlamalar obyekti beriladi:fetch(url, { method: "POST", headers, body }). JSON yuborsangiz,body: JSON.stringify(obyekt)va"Content-Type": "application/json"sarlavhasini o'zingiz qo'yasiz.FormDatavaURLSearchParamsda esaContent-Typeni brauzer o'zi qo'yadi —FormDatauchun uni qo'lda yozish hatto xato.
Bu darsda
fetchningmethod,headersvabodysozlamalarini ishlata olasiz.- Obyektni JSON qilib yuborasiz va serverning
201,400,415,422javoblarini to'g'ri o'qiysiz. FormDatavaURLSearchParamsni so'rov tanasi sifatida yuborasiz va farqini tushuntira olasiz.- Har bir tana turi uchun
Content-Typeqanday bo'lishini oldindan ayta olasiz. - Bron formasini haqiqiy serverga jo'natib, xatolarni maydonlar yonida ko'rsata olasiz.
Oldin bilishingiz kerak: fetch asoslari, FormData, Forma qiymatlarini o'qish va submit, Parametrda destructuring va options obyekti, HTTP metodlari va status kodlari.
1. Nega bu kerak?
Oldingi darsda «Bahor» menyusini serverdan oldik. Lekin sayt faqat o'qish uchun emas. Mehmon stol bron qiladi, izoh qoldiradi, buyurtma beradi — bu ma'lumotlar serverga borishi kerak.
FormData darsida bron formasini yig'ishni o'rgandik. Lekin u yerda "server"ni setTimeout bilan taqlid qilgan edik: 800 ms kutardik va "Bron qabul qilindi" deb yozardik. Haqiqatda hech narsa hech qayerga ketmagan edi.
Bugun shu formani haqiqiy serverga jo'natamiz. Buning uchun fetch ga uch narsani aytish kerak:
- Qanday so'rov — metod:
POST,PUT,PATCH,DELETE. - Nima yuboryapmiz — tana (body).
- U qanday formatda —
Content-Typesarlavhasi.
Uchinchisi eng ko'p xato qilinadigan joy. Pochta o'xshatishi bilan: qutiga narsa soldingiz (tana), lekin ustiga "ichida shisha" deb yozmadingiz (Content-Type). Pochtachi qutini ochib nima qilishni bilmaydi.
2. fetch ning sozlamalar obyekti
2.1 Ikkinchi argument
Parametrda destructuring va options obyekti darsida fetch ni misol qilib aytgan edik: manzil — asosiy argument, method kabi sozlamalar — options obyektida; method berilmasa, "GET" ishlaydi. Endi uni o'zimiz yozamiz:
fetch(url, {
method: "POST", // so'rov turi
headers: { ... }, // so'rov sarlavhalari
body: ..., // yuboriladigan tana
});Uchala sozlama ham ixtiyoriy. Hech biri berilmasa — oddiy GET, oldingi darsdagidek.
2.2 Aks-sado: so'rovingizni ko'ring
Mashq API'sida maxsus endpoint bor — /api/mashq/aks. U so'rovni qayta ishlamaydi, balki o'zini qaytaradi: qaysi metod keldi, qaysi sarlavhalar, tanada nima bor. Ko'zgu kabi — fetch aslida nima yuborganini o'z ko'zingiz bilan ko'rasiz.
async function aksniKor() {
const javob = await fetch("https://ilmhamroh.uz/api/mashq/aks", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ taom: "Osh", soni: 2 }),
});
console.log(await javob.json());
}
aksniKor();Konsolda:
{
metod: 'POST',
yol: '/api/mashq/aks',
sorov: {},
sarlavhalar: { 'content-type': 'application/json', authorization: "yo'q" },
tana: { taom: 'Osh', soni: 2 }
}Server bizning obyektimizni qaytarib berdi: tana: { taom: 'Osh', soni: 2 }. sarlavhalar da u ikkitasini ko'rsatadi: content-type (biz qo'ydik) va authorization (kirish tokeni bormi — keyinroq, Autentifikatsiyali so'rovlar darsida). sorov — URL'dagi ?... parametrlari, bu safar bo'sh.
aks — bu dars davomidagi asosiy "tekshiruv asbobimiz". Shubha bo'lsa — so'rovni aks ga yuboring va nima ketganini ko'ring.
3. JSON yuborish
3.1 Uch shart
API'lar bilan eng ko'p ishlatiladigan format — JSON. JSON yuborish uchun uchta narsa kerak:
method: "POST"(yokiPUT,PATCH).body: JSON.stringify(obyekt)— obyektni JSON matniga aylantirish (JSON asoslari). Tarmoq orqali obyekt emas, faqat matn yoki baytlar ketadi.headers: { "Content-Type": "application/json" }— serverga "bu matn JSON" deb aytish.
3.2 Haqiqiy bron
/api/mashq/bronlar — stol bron qilish endpoint'i. U ism, odamlar, sana va vaqt ni kutadi; telefon ixtiyoriy. Dilshod aka 10-oktabr kuni soat 19:00 ga to'rt kishilik stol bron qilyapti:
const API = "https://ilmhamroh.uz/api/mashq";
async function bronQil(bron) {
const javob = await fetch(`${API}/bronlar`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(bron),
});
console.log(javob.status, javob.headers.get("Location"));
console.log(await javob.json());
}
bronQil({
ism: "Dilshod aka",
odamlar: 4,
sana: "2026-10-10",
vaqt: "19:00",
});Konsolda:
201 /api/mashq/bronlar/5897
{
id: 5897,
ism: 'Dilshod aka',
odamlar: 4,
sana: '2026-10-10',
vaqt: '19:00',
holat: 'qabul qilindi'
}Javobni o'qiymiz:
201 Created— "yaratildi".200dan farqi: server yangi narsa (bron) yaratdi (HTTP metodlari va status kodlari).Locationsarlavhasi — yangi bronning manzili. Ko'p API'lar201bilan birga shuni qaytaradi.- Tana — saqlangan bron: biz yuborgan maydonlar, server bergan
idvaholat.
id — 5897. Bu son tasodifiy emas: mashq serveri uni ma'lumotdan hisoblaydi. Bir xil bronni qayta yuborsangiz — yana 5897. Shu sababli darsdagi natija sizda ham aynan shunday chiqadi.
Maslahat: Mashq serveri bronni hech qayerga saqlamaydi — faqat tekshiradi va javob beradi.
Locationdagi/api/mashq/bronlar/5897ni ochsangiz,404olasiz. Haqiqiy serverda esa u yerda saqlangan bron turardi.
3.3 Server rad etganda: 422
Endi xato ma'lumot yuboramiz: bir harfli ism, 0 ta odam, 30-fevral va kechasi 23:30:
async function xatoBron() {
const url = "https://ilmhamroh.uz/api/mashq/bronlar";
const javob = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
ism: "D",
odamlar: 0,
sana: "2026-02-30",
vaqt: "23:30",
}),
});
const malumot = await javob.json();
console.log(javob.status, malumot.xato);
for (const [maydon, sabab] of Object.entries(malumot.maydonlar)) {
console.log(`- ${maydon}: ${sabab}`);
}
}
xatoBron();Konsolda:
422 Ma'lumot noto'g'ri
- ism: 2 dan 40 gacha belgi bo'lishi kerak
- odamlar: 1 dan 20 gacha bo'lishi kerak
- sana: YYYY-MM-DD ko'rinishidagi haqiqiy sana bo'lishi kerak
- vaqt: 10:00 dan 22:00 gacha bo'lishi kerak422 Unprocessable Content — "so'rov to'g'ri tuzilgan, lekin ma'lumot qoidaga zid". JSON yaroqli, server uni o'qidi — lekin qiymatlar noto'g'ri. Mashq serveri qaysi maydon nega xato ekanini maydonlar obyektida aytadi. Object.entries — obyektni [kalit, qiymat] juftliklariga aylantiradi (Obyekt bo'ylab yurish).
Bron vaqti 10:00 dan 22:00 gacha. «Bahor» 7:00 da ochilsa ham, ertalab stol bron qilinmaydi.
Esingizdami, fetch 422 da ham xato bermaydi (fetch asoslari). Shuning uchun biz status ni o'qib, xatoni o'zimiz ko'rsatdik. Bu xatolarni formada, har maydon yonida chiqarishni dars oxiridagi «Bron formasi» bo'limida qilamiz.
Tekshirib ko'ring: Brauzer formada
requiredvamin="1"bor. Server baribir tekshirishi kerakmi?
Javob
Ha, albatta. Brauzer tekshiruvi — foydalanuvchiga qulaylik. Uni DevTools'da o'chirish yoki so'rovni formasiz, to'g'ridan-to'g'ri fetch bilan yuborish mumkin — xuddi biz hozir qilganimizdek. Server esa hech kimga ishonmaydi va har bir so'rovni o'zi tekshiradi. 422 javobi — aynan shu tekshiruv natijasi.
4. Content-Type ni unutsangiz
4.1 415: "bu turdagi ma'lumot qabul qilinmaydi"
HTTP sarlavhalari darsida ogohlantirgan edik: "JSON yuborib, Content-Type ni unutish — server tanani JSON deb tanimaydi". Endi buni haqiqiy serverda ko'ramiz. Sarlavhani olib tashlaymiz:
async function sarlavhasiz() {
const url = "https://ilmhamroh.uz/api/mashq/bronlar";
const javob = await fetch(url, {
method: "POST",
body: JSON.stringify({ ism: "Dilshod aka", odamlar: 4 }),
});
console.log(javob.status, await javob.json());
}
sarlavhasiz();Konsolda:
415 {
xato: "Content-Type application/json bo'lishi kerak",
keldi: 'text/plain'
}415 Unsupported Media Type — "bu turdagi ma'lumotni qabul qilmayman". Va keldi: 'text/plain' — qiziq! Biz hech qanday tur aytmagan edik. Kim text/plain deb yozdi?
fetch ning o'zi. Tanaga satr bersangiz, fetch uni oddiy matn deb hisoblaydi va Content-Type: text/plain;charset=UTF-8 ni avtomatik qo'yadi. JSON.stringify natijasi — oddiy satr, fetch uning ichida JSON borligini bilmaydi. Shuning uchun JSON uchun sarlavhani har doim o'zingiz qo'yasiz.
4.2 stringify ni unutsangiz
Teskari xato — sarlavha bor, lekin obyekt to'g'ridan-to'g'ri body ga berilgan:
async function stringifySiz() {
const javob = await fetch("https://ilmhamroh.uz/api/mashq/aks", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: { ism: "Dilshod aka" },
});
console.log(javob.status, await javob.json());
}
stringifySiz();Konsolda:
400 { xato: 'JSON buzilgan' }fetch obyektni JSON qilishni bilmaydi. U obyektni String() bilan satrga aylantirdi — natija "[object Object]" (Turlarni almashtirish). Serverga [object Object] degan matn bordi, "bu JSON" degan yorliq bilan. Server uni tahlil qila olmadi — 400 Bad Request.
Xato jim o'tib ketmagani yaxshi: server ogohlantirdi. Ba'zi serverlar bunday holatda bo'sh obyekt deb qabul qilib yuboradi — unda xatoni topish ancha qiyin.
Tekshirib ko'ring: Uchta xato javobni farqlang: 400, 415, 422. Qaysi biri "so'rovni umuman o'qiy olmadim", qaysi biri "o'qidim, lekin qiymatlar noto'g'ri"?
Javob
415 — "bu turdagi tanani qabul qilmayman" (yorliq noto'g'ri). 400 — "tana buzilgan, o'qiy olmadim" (yorliq JSON, ichi esa JSON emas). 422 — "o'qidim, tuzilishi to'g'ri, lekin qiymatlar qoidaga zid". Xatoni tuzatish joyi ham shundan bilinadi: 415 va 400 — kodingizda, 422 — foydalanuvchi kiritgan ma'lumotda.
5. Formadan yuborish: URLSearchParams va FormData
5.1 URLSearchParams — oddiy forma formati
HTML forma method="post" bilan o'zi yuborilganda, ma'lumot ism=Dilshod+aka&odamlar=4 ko'rinishida ketadi (Forma qanday ishlaydi). Bu format application/x-www-form-urlencoded deyiladi. JavaScript'da uni URLSearchParams obyekti yasaydi:
const parametrlar = new URLSearchParams({
ism: "Dilshod aka",
izoh: "piyozsiz & achchiq",
});
console.log(parametrlar.toString());Konsolda:
ism=Dilshod+aka&izoh=piyozsiz+%26+achchiqBo'sh joy + ga, & belgisi esa %26 ga aylandi. Nega? & bu formatda juftliklarni ajratadi. Matn ichidagi & ni "kodlamasa", server achchiq ni alohida maydon deb o'ylardi. URLSearchParams buni o'zi qiladi — qo'lda satr yig'ishdan shuning uchun yaxshi. URLSearchParams ning boshqa imkoniyatlari — URL va URLSearchParams darsida.
Uni body ga beramiz. Content-Type ni yozmaymiz:
async function formaFormatida() {
const url = "https://ilmhamroh.uz/api/mashq/bronlar";
const javob = await fetch(url, {
method: "POST",
body: new URLSearchParams({
ism: "Dilshod aka",
odamlar: "4",
sana: "2026-10-10",
vaqt: "19:00",
}),
});
console.log(javob.status, (await javob.json()).id);
}
formaFormatida();Konsolda:
201 5897O'sha bron, o'sha id. fetch URLSearchParams ni tanidi va Content-Type: application/x-www-form-urlencoded;charset=UTF-8 ni o'zi qo'ydi. E'tibor bering: odamlar — "4", satr. Bu formatda hamma qiymat satr bo'ladi; mashq serveri "4" ni songa o'zi aylantiradi.
5.2 FormData — fayllar bilan
FormData darsida "fayl ham FormData ning ichida qoladi; uni fetch bilan jo'natganda brauzer kerakli multipart/form-data shaklini o'zi tanlaydi" degan edik. Sinaymiz. Formadagi fayl maydonini kodda File obyekti bilan almashtiramiz — 5 baytli izoh.txt:
async function faylBilan() {
const malumot = new FormData();
malumot.append("ism", "Dilshod aka");
malumot.append(
"rasm",
new File(["salom"], "izoh.txt", { type: "text/plain" }),
);
const javob = await fetch("https://ilmhamroh.uz/api/mashq/aks", {
method: "POST",
body: malumot,
});
const aks = await javob.json();
console.log(aks.sarlavhalar["content-type"].split(";")[0]);
console.log(aks.tana);
}
faylBilan();Konsolda:
multipart/form-data
[
{ nom: 'ism', qiymat: 'Dilshod aka' },
{ nom: 'rasm', fayl: 'izoh.txt', hajm: 5, tur: 'text/plain' }
]multipart/form-data — "ko'p qismli" format: tana bir nechta qismga bo'linadi, har qism — alohida maydon, fayllar esa o'z nomi va turi bilan. Aks-sado har qismni ko'rsatdi: oddiy maydon qiymat bilan, fayl — nomi, hajmi (5 bayt) va turi bilan.
Nega split(";")[0]? To'liq sarlavha multipart/form-data; boundary=----... ko'rinishida. Boundary (chegara) — qismlarni ajratuvchi tasodifiy satr, har so'rovda yangi. Uni chiqarmadik, chunki har safar boshqacha.
File — fayl obyekti, File va Blob darsida batafsil. Haqiqiy formada u <input type="file"> dan keladi va new FormData(forma) uni o'zi qo'shadi.
5.3 FormData da Content-Type ni qo'lda yozmang
Ko'p uchraydigan xato: "multipart yuboryapman, demak sarlavhada aytishim kerak":
async function qoldaYozilgan() {
const malumot = new FormData();
malumot.append("ism", "Dilshod aka");
const javob = await fetch("https://ilmhamroh.uz/api/mashq/aks", {
method: "POST",
headers: { "Content-Type": "multipart/form-data" },
body: malumot,
});
console.log(javob.status, await javob.json());
}
qoldaYozilgan();Konsolda:
400 { xato: "multipart/form-data buzilgan (boundary yo'q)" }Siz yozgan sarlavha fetch nikini almashtirdi — va unda boundary yo'q. Server qismlar qayerda bo'linishini bilmaydi. Qoida: FormData va URLSearchParams da Content-Type ni yozmang — fetch uni to'g'ri, boundary bilan qo'yadi.
5.4 Server FormData ni qabul qilmasa
/bronlar faqat JSON yoki forma formatini (urlencoded) qabul qiladi. Unga FormData yuborsangiz — 415 va keldi: 'multipart/form-data'. Bunday holatda ikki yo'l bor:
// 1) FormData → URLSearchParams (fayl bo'lmasa)
body: new URLSearchParams(new FormData(forma))
// 2) FormData → obyekt → JSON
body: JSON.stringify(Object.fromEntries(new FormData(forma)))Ikkinchi yo'lda bitta tuzoq bor: formadan kelgan hamma qiymat — satr. odamlar: "4" JSON'da ham satr bo'lib ketadi va mashq serveri 422 qaytaradi: odamlar: "butun son bo'lishi kerak". Forma formatida server satrni o'zi songa aylantiradi, JSON'da esa turlar qat'iy. Shuning uchun JSON'dan oldin sonlarni Number() bilan aylantiring — natijadagi kod shunday qiladi.
6. Content-Type qoidalari — bitta jadvalda
body ga nima berasiz |
fetch qo'yadigan Content-Type |
O'zingiz yozasizmi? |
|---|---|---|
JSON.stringify(...) (satr) |
text/plain;charset=UTF-8 |
ha: application/json |
URLSearchParams |
application/x-www-form-urlencoded;charset=UTF-8 |
yo'q |
FormData |
multipart/form-data; boundary=... |
yo'q, yozmang |
Blob / File |
uning type i |
odatda yo'q |
Qaysi formatni tanlashni sxemadan ko'ring:
flowchart TD
A{"Fayl bormi?"} -->|"ha"| F["FormData<br/>(Content-Type yozmang)"]
A -->|"yo'q"| B{"Server nimani<br/>kutadi?"}
B -->|"JSON (ko'p API)"| J["JSON.stringify +<br/>application/json"]
B -->|"oddiy forma"| U["URLSearchParams<br/>(Content-Type yozmang)"]Zamonaviy API'larning ko'pchiligi JSON kutadi. Fayl yuklash — deyarli doim FormData. Qaysi birini kutishini API hujjatidan bilasiz.
Tekshirib ko'ring:
body: "osh"bilanPOSTyuborildi, sarlavhasiz. Server qandayContent-Typeko'radi?
Javob
text/plain;charset=UTF-8. Tana — satr, fetch satr uchun shu turni avtomatik qo'yadi. aks ga yuborsangiz, tana: 'osh' va shu sarlavhani qaytaradi.
7. Boshqa metodlar: PUT, PATCH, DELETE
7.1 HTML forma qila olmaydigan ish
Forma qanday ishlaydi darsida ogohlantirgan edik: method="put" yozsangiz, brauzer jimgina GET yuboradi — HTML forma faqat GET va POST biladi. fetch esa istalgan metodni yubora oladi:
const API = "https://ilmhamroh.uz/api/mashq";
const json = { "Content-Type": "application/json" };
async function metodlar() {
const sorovlar = [
{ method: "PUT", headers: json, body: '{"narx":36000}' },
{ method: "PATCH", headers: json, body: '{"narx":36000}' },
{ method: "DELETE" },
];
for (const sozlama of sorovlar) {
const javob = await fetch(`${API}/aks`, sozlama);
const aks = await javob.json();
console.log(aks.metod, aks.tana);
}
}
metodlar();Konsolda:
PUT { narx: 36000 }
PATCH { narx: 36000 }
DELETE nullMa'nosini HTTP metodlari darsidan eslang: PUT — butunlay almashtirish, PATCH — qisman o'zgartirish, DELETE — o'chirish. DELETE odatda tanasiz. So'rovlar for...of ichida await bilan ketma-ket ketdi — shuning uchun konsol tartibi har doim bir xil (Ketma-ket va parallel bajarish).
Bu metodlarni haqiqiy ma'lumot bilan — vazifalar ro'yxatini yaratish, o'zgartirish, o'chirish — API klient qatlami darsida ishlatamiz.
7.2 Metod nomini katta harfda yozing
fetch get, post, put, delete, head, options ni o'zi katta harfga aylantiradi. patch ni esa aylantirmaydi — standart shunday. method: "patch" bilan so'rov serverga kichik harfda boradi. Node 24 buni sezib, ogohlantiradi:
[UNDICI-FETCH-patch] Warning: Using `patch` is highly likely to result in a `405 Method Not Allowed`. `PATCH` is much more likely to succeed.Tarjimasi: "patch ishlatish deyarli aniq 405 Method Not Allowed ga olib keladi. PATCH ancha ko'proq ishlaydi." Mashq serverimizda esa undan ham oldin, veb-server darajasida, 400 Bad Request keladi. Brauzerda esa so'rov CORS tekshiruvidan o'tmaydi (CORS mijoz tomondan). Qoida: metodni doim katta harfda yozing: "PATCH".
7.3 GET ga tana berib bo'lmaydi
async function sinab() {
await fetch("https://ilmhamroh.uz/api/mashq/aks", {
method: "GET",
body: "osh",
});
}
sinab();Node 24 da: TypeError: Request with GET/HEAD method cannot have body. Chrome'da xabar oldiga Failed to execute 'fetch' on 'Window': qo'shiladi. Tarjimasi: "GET yoki HEAD so'rovida tana bo'lishi mumkin emas." GET bilan qo'shimcha ma'lumot kerak bo'lsa — URL parametrlariga (?turkum=taom) qo'ying.
Tekshirib ko'ring: Sardor oshning narxini 36 000 ga o'zgartirmoqchi, taomning qolgan maydonlari (nomi, turkumi) o'z joyida qolsin.
PUTmi yokiPATCHmi?method: "patch"deb yozsa nima bo'ladi?
Javob
PATCH — faqat bitta maydon o'zgaryapti, bu qisman o'zgartirish. PUT esa butun taomni almashtiradi: unga hamma maydonni yuborish kerak bo'lardi. Kichik harfli "patch" ni esa fetch katta harfga aylantirmaydi. Natija: Node ogohlantiradi va server 400/405 qaytaradi, brauzerda esa CORS xatosi chiqadi.
8. Bron formasi — haqiqiy serverga
Endi hammasini birlashtiramiz. Forma qiymatlarini o'qish va submit darsidagi naqsh: submit → preventDefault → ma'lumotni yig'ish → serverga fetch → natijani ko'rsatish. Formada qiymatlar oldindan to'ldirilgan. «Bron qilish» ni bosing, keyin odamlar sonini 0 ga, vaqtni 23:30 ga o'zgartirib, yana bosing:
<style>
body { font: 1rem/1.5 system-ui, sans-serif; margin: 1rem; }
label { display: block; margin: 0.4rem 0; }
input { font: inherit; padding: 0.2rem 0.4rem; }
button { font: inherit; padding: 0.4rem 0.8rem; }
.xato { color: #b3261e; font-size: 0.9rem; margin-left: 0.4rem; }
#natija { font-weight: 600; }
</style>
<form id="bron" novalidate>
<label>Ism <input name="ism" value="Dilshod aka"></label>
<label>Odamlar
<input name="odamlar" type="number" value="4"></label>
<label>Sana
<input name="sana" type="date" value="2026-10-10"></label>
<label>Vaqt <input name="vaqt" type="time" value="19:00"></label>
<button type="submit">Bron qilish</button>
</form>
<p id="natija" role="status"></p>
<script>
const API = "https://ilmhamroh.uz/api/mashq";
const forma = document.getElementById("bron");
const natija = document.getElementById("natija");
function xatolarniTozala() {
for (const s of forma.querySelectorAll(".xato")) s.remove();
}
function xatoniKorsat(maydon, matn) {
const input = forma.elements[maydon];
const span = document.createElement("span");
span.className = "xato";
span.textContent = matn;
input.after(span);
}
forma.addEventListener("submit", async (event) => {
event.preventDefault();
const tugma = event.submitter;
const bron = Object.fromEntries(new FormData(forma));
bron.odamlar = Number(bron.odamlar);
tugma.disabled = true;
natija.textContent = "Yuborilmoqda...";
xatolarniTozala();
try {
const javob = await fetch(`${API}/bronlar`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(bron),
});
const malumot = await javob.json();
if (javob.status === 201) {
natija.textContent = `Bron qabul qilindi: №${malumot.id}`;
console.log("201, id:", malumot.id);
} else if (javob.status === 422) {
natija.textContent = "Ma'lumotni tekshiring.";
const xatolar = malumot.maydonlar;
for (const [maydon, matn] of Object.entries(xatolar)) {
xatoniKorsat(maydon, matn);
}
console.log("422:", Object.keys(xatolar).join(", "));
} else {
natija.textContent = `Server xatosi: ${javob.status}`;
}
} catch (xato) {
natija.textContent = "Internet bilan muammo. Qayta urining.";
} finally {
tugma.disabled = false;
}
});
</script>Nimani ko'rdingiz:
- Birinchi bosishda: "Yuborilmoqda..." va bir lahzadan keyin "Bron qabul qilindi: №5897". Konsolda
201, id: 5897. 0odam va23:30bilan: maydonlar yonida qizil xabarlar — "1 dan 20 gacha bo'lishi kerak", "10:00 dan 22:00 gacha bo'lishi kerak". Konsolda422: odamlar, vaqt.- Yuborish davomida tugma o'chiq —
FormDatadarsidagi ikki marta bosishdan himoya. Endi usetTimeoutni emas, haqiqiy server javobini kutadi.finally— javob qanday bo'lmasin, tugmani qayta yoqadi.
Kodda uchta muhim qaror bor:
bron.odamlar = Number(bron.odamlar)— formadan kelgan"4"ni songa aylantirish. Bu qatorni o'chirib ko'ring: serverodamlar: butun son bo'lishi kerakdeydi.novalidate— brauzerning o'z tekshiruvini o'chirdik, server xatolarini ko'rishingiz uchun. Haqiqiy saytda ikkalasi ham bo'ladi: brauzer tekshiruvi — tez yordam, server tekshiruvi — kafolat.422va boshqa xatolar alohida:422— foydalanuvchi tuzatadi;500yoki tarmoq xatosi — "keyinroq urinib ko'ring".
Xato matnlari textContent bilan qo'yildi — server matni HTML sifatida o'qilmaydi (Kontentni o'zgartirish va XSS xavfi).
9. Hujumchi nigohi
1. Brauzer tekshiruvini aylanib o'tish. Hujumchi formani ishlatmaydi. U DevTools konsolida o'zi fetch yozadi yoki curl bilan odamlar: -5, ism: "<script>..." yuboradi. required, min, maxlength — hech biri ishlamaydi. Qarshi chora: server har maydonni o'zi tekshiradi — mashq serveri buni 422 bilan ko'rsatdi. Brauzer tekshiruvi — faqat qulaylik, himoya emas.
2. Maxfiy ma'lumotni URL'da yuborish. fetch("/kirish?parol=bahor123") — GET va parametr URL'da. URL esa brauzer tarixida, server loglarida, Referer sarlavhasida qoladi. Qarshi chora: parol, karta raqami, token — faqat POST tanasida (va HTTPS orqali). Kirish so'rovini Autentifikatsiyali so'rovlar darsida aynan shunday yuboramiz.
10. Ko'p uchraydigan xatolar
10.1 JSON uchun Content-Type yo'q
Server 415 qaytaradi yoki tanani bo'sh deb o'qiydi. Tuzatish: headers: { "Content-Type": "application/json" }.
10.2 JSON.stringify yo'q
Tanaga [object Object] ketadi — 400. Tuzatish: body: JSON.stringify(obyekt).
10.3 FormData ga qo'lda Content-Type
boundary yo'qoladi — server tanani bo'la olmaydi. Tuzatish: sarlavhani olib tashlang.
10.4 Formadagi sonlar — satr
Object.fromEntries(new FormData(forma)) da hamma qiymat satr. JSON API'ga yuborishdan oldin sonlarni Number() bilan, belgilash katagini === "on" bilan aylantiring.
10.5 Javobni tekshirmasdan "muvaffaqiyat" deyish
await fetch(url, { method: "POST", body });
natija.textContent = "Bron qabul qilindi!"; // ❌ 422 bo'lsa hamfetch 422 da ham bajariladi. Tuzatish: javob.ok yoki aniq status ni tekshiring, keyin xabar chiqaring.
10.6 patch kichik harfda
Node'da ogohlantirish va 400/405, brauzerda CORS xatosi. Tuzatish: method: "PATCH".
11. Mashqlar
1-mashq (oson): Buyurtmani aks ettiring
/api/mashq/aks ga POST bilan { taom: "Manti", soni: 3, stol: 5 } ni JSON qilib yuboring. Javobdan faqat tana ni chiqaring. Ishora: uchta sozlama — method, headers, body.
Yechim
async function buyurtmaYubor() {
const javob = await fetch("https://ilmhamroh.uz/api/mashq/aks", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ taom: "Manti", soni: 3, stol: 5 }),
});
const aks = await javob.json();
console.log(aks.tana);
}
buyurtmaYubor();Konsolda:
{ taom: 'Manti', soni: 3, stol: 5 }Server obyektni o'zgarishsiz qaytardi. Sonlar son bo'lib qoldi — JSON turlarni saqlaydi.
2-mashq (o'rta): bronYubor funksiyasi
bronYubor(bron) funksiyasini yozing. U /bronlar ga JSON yuborsin va natijani bitta shaklda qaytarsin: muvaffaqiyatda { ok: true, id }, 422 da { ok: false, xatolar } (maydonlar obyekti), boshqa statusda Error tashlasin. Ikki holatni sinang: to'g'ri bron va odamlar: 25.
Yechim
async function bronYubor(bron) {
const url = "https://ilmhamroh.uz/api/mashq/bronlar";
const javob = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(bron),
});
const malumot = await javob.json();
if (javob.status === 201) return { ok: true, id: malumot.id };
if (javob.status === 422) {
return { ok: false, xatolar: malumot.maydonlar };
}
throw new Error(`Kutilmagan javob: ${javob.status}`);
}
async function sina() {
const asos = {
ism: "Dilshod aka",
sana: "2026-10-10",
vaqt: "19:00",
};
console.log(await bronYubor({ ...asos, odamlar: 4 }));
console.log(await bronYubor({ ...asos, odamlar: 25 }));
}
sina();Konsolda:
{ ok: true, id: 5897 }
{ ok: false, xatolar: { odamlar: "1 dan 20 gacha bo'lishi kerak" } }Funksiya chaqiruvchidan HTTP tafsilotlarini yashiradi: u faqat "bo'ldimi, bo'lmasa nima xato" degan javobni oladi. Yozuvdagi { ...asos, odamlar: 4 } — umumiy maydonlarga bittasini qo'shish (spread). 422 — kutilgan holat (foydalanuvchi xatosi), shuning uchun u oddiy natija sifatida qaytadi; kutilmagan status esa throw. Bunday "API funksiyalari"ni API klient qatlami darsida bitta modulga yig'amiz.
3-mashq (qiyin): Uch formatni solishtiring
Bitta bron ma'lumotini /aks ga uch xil yuboring: JSON, URLSearchParams va FormData. Har biri uchun Content-Type ning ; gacha qismini va odamlar qiymatining turini (typeof) chiqaring. Faylni kurs/mashqlar/11/18-yuborish/formatlar.mjs ga saqlang.
Ishora: FormData uchun aks javobidagi tana — massiv: { nom, qiymat } qismlari. Undan odamlar ni find bilan toping (find).
Yechim
const AKS = "https://ilmhamroh.uz/api/mashq/aks";
const bron = { ism: "Dilshod aka", odamlar: 4 };
const JSON_SARLAVHA = { "Content-Type": "application/json" };
function tanalar() {
const fd = new FormData();
fd.append("ism", bron.ism);
fd.append("odamlar", String(bron.odamlar));
return [
["JSON", JSON.stringify(bron), JSON_SARLAVHA],
["URLSearchParams", new URLSearchParams(fd)],
["FormData", fd],
];
}
async function solishtir() {
for (const [nom, body, headers] of tanalar()) {
const javob = await fetch(AKS, { method: "POST", headers, body });
const aks = await javob.json();
const tur = aks.sarlavhalar["content-type"].split(";")[0];
const odamlar = Array.isArray(aks.tana)
? aks.tana.find((q) => q.nom === "odamlar").qiymat
: aks.tana.odamlar;
console.log(`${nom}: ${tur}, odamlar — ${typeof odamlar}`);
}
}
solishtir();Konsolda:
JSON: application/json, odamlar — number
URLSearchParams: application/x-www-form-urlencoded, odamlar — string
FormData: multipart/form-data, odamlar — stringFaqat JSON sonni son sifatida saqlaydi. Forma formatlarida hamma narsa matn — sonlarga aylantirish serverning ishi. headers uchinchi elementi bo'lmagan qatorlarda undefined — fetch buni "sarlavha yo'q" deb tushunadi.
git add 11/18-yuborish/formatlar.mjs
git commit -m "11/18: uch xil tana formatini solishtir"12. Real ishda
- Har bir forma. Ro'yxatdan o'tish, izoh, savatga qo'shish, Click/Payme to'lov sahifasiga yo'naltirishdan oldingi buyurtma — hammasi
POST+ JSON. DevTools → Network → so'rovni bosing → Payload tabida yuborilgan tanani ko'rasiz. - Fayl yuklash. Avatar, hujjat, rasm —
FormDatabilan. Yuklash progressini ko'rsatish — Fayl yuklash va progress darsida. - Xatolar shartnomasi. Jamoalar "422 da
maydonlarobyekti keladi" kabi qoidani oldindan kelishib oladi. Shunda frontend har xatoni maydon yonida ko'rsata oladi. Backend tomonini Express va NestJS qismlarida o'zingiz yozasiz. - Intervyu. "
FormDatayuborgandaContent-Typeni qo'yish kerakmi?" — "Yo'q,boundaryni brauzer qo'yadi". "400 va 422 farqi?" — bugungi jadval.
Xulosa
- Ma'lumot yuborish:
fetch(url, { method, headers, body }).methodbo'lmasa —GET. - JSON:
body: JSON.stringify(obyekt)+"Content-Type": "application/json"— sarlavhani o'zingiz qo'yasiz. URLSearchParamsvaFormDatauchunContent-Typenifetcho'zi qo'yadi;FormDatada uni qo'lda yozishboundaryni buzadi.- Javoblar:
201— yaratildi (+Location),400— tana buzilgan,415— tur noto'g'ri,422— qiymatlar noto'g'ri. - Formadan kelgan qiymatlar — satr; JSON'dan oldin sonlarni aylantiring. Server baribir hammasini o'zi tekshiradi.
- Metod nomlari — katta harfda;
GETga tana berilmaydi.
Keyingi dars: Request, Response, Headers va fetch opsiyalari — fetch ning ichidagi uchta obyekt va kamroq ko'rinadigan, lekin muhim sozlamalar: cookie, kesh, yo'naltirish va sahifa yopilganda ham yetib boradigan so'rov.
Manbalar
- MDN: "Using the Fetch API" (Setting a body, Setting headers), "FormData", "URLSearchParams" — developer.mozilla.org
- WHATWG Fetch Standard: "BodyInit", "extract a body" — fetch.spec.whatwg.org
- RFC 9110: HTTP Semantics — 201, 400, 415, 422 status kodlari
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!