IlmHamroh
JavaScript Full-stack/11-qism. Asinxron JavaScript va tarmoq19/32-dars19 daqiqa
Mundarija (39)

fetch Request, Response va Headers: so'rov opsiyalari, kesh, cookie va yo'naltirish

Qisqacha: fetch ichida uchta obyekt ishlaydi: Request (so'rov), Response (javob) va ikkalasidagi Headers (sarlavhalar). Sozlamalar obyekti so'rovning xulqini boshqaradi: credentials — cookie yuborilsinmi, cache — HTTP keshdan foydalanilsinmi, redirect — yo'naltirishga ergashilsinmi, keepalive — sahifa yopilsa ham so'rov yetib borsinmi. Javob tanasini ikki marta o'qish kerak bo'lsa — response.clone().

Bu darsda

  • Headers obyektini yaratib, get, set, append, has, delete bilan boshqara olasiz.
  • Request obyektini yasab, uni qayta ishlatish qoidasini bilasiz.
  • Response ning type, redirected, bodyUsed xususiyatlarini va clone() ni ishlata olasiz.
  • credentials, mode, cache, redirect, keepalive, priority, signal opsiyalari nima qilishini tushuntira olasiz.
  • Brauzer va Node fetch i qayerda farq qilishini bilasiz.

Oldin bilishingiz kerak: fetch asoslari, fetch bilan ma'lumot yuborish, HTTP sarlavhalari: MIME, cookie va kesh, Bekor qilish: AbortController.

1. Nega bu kerak?

Sardor «Bahor» sayti uchun fetch bilan ancha kod yozdi. Ishlayapti, lekin to'rtta savol paydo bo'ldi:

  1. Har so'rovga bir xil sarlavhalarni qo'lda yozyapti. Ularni bitta joyda saqlab, kerakli joyda biroz o'zgartirish mumkinmi?
  2. Xatoni tekshirish uchun javob matnini logga yozmoqchi — lekin keyin json() "tana allaqachon o'qilgan" deydi.
  3. Mehmon sahifani yopganda "sahifa yopildi" degan statistikani serverga yubormoqchi. So'rov yetib boradimi?
  4. Server so'rovni boshqa manzilga yo'naltirdi. Kod buni qanday sezadi?

To'rtalasining javobi fetch ning kamroq ko'rinadigan qismida. Oldingi ikki darsda method, headers, body ni ishlatdik. Bugun qolgan sozlamalarni va fetch ichidagi obyektlarni ochamiz.

2. Uchta obyekt

fetch(url, sozlamalar) chaqirganingizda ichkarida shunday bo'ladi:

flowchart LR
  U["url +<br/>sozlamalar"] --> R["Request<br/>(so'rov)"]
  R -- "fetch()" --> S[("Server")]
  S --> P["Response<br/>(javob)"]
  R -.- H1["Headers"]
  P -.- H2["Headers"]

Sxemaga qarang: manzil va sozlamalardan Request obyekti yasaladi, server javobidan esa Response obyekti. Ikkalasining ham sarlavhalari — alohida Headers obyekti. Bularni o'zingiz ham yasashingiz mumkin — new Headers(), new Request(), new Response(). Uchalasi brauzerda ham, Node'da ham global.

3. Headers — sarlavhalar to'plami

3.1 Yaratish va o'zgartirish

Headers — sarlavhalarni saqlaydigan obyekt. U oddiy obyektga o'xshaydi, lekin HTTP qoidalarini biladi:

js
const sarlavhalar = new Headers({ Accept: "application/json" });

sarlavhalar.set("Content-Type", "application/json");
sarlavhalar.append("X-Sinov", "bir");
sarlavhalar.append("X-Sinov", "ikki");

console.log(sarlavhalar.get("accept"));
console.log(sarlavhalar.has("ACCEPT"));
for (const [nom, qiymat] of sarlavhalar) {
  console.log(nom, "=", qiymat);
}

Konsolda:

text
application/json
true
accept = application/json
content-type = application/json
x-sinov = bir, ikki

Uchta muhim xulq:

  • Katta-kichik harf ahamiyatsiz. Accept, accept, ACCEPT — bitta sarlavha. HTTP standarti shunday deydi. Ichkarida nomlar kichik harfda saqlanadi.
  • set almashtiradi, append qo'shadi. Bir nomga ikki marta append — qiymatlar vergul bilan birlashadi: bir, ikki.
  • Aylanish tartibi — alifbo bo'yicha. for...of sarlavhalarni nomi bo'yicha saralab beradi, qo'shilgan tartibda emas.

delete(nom) — sarlavhani o'chiradi. Headers ni fetch ga to'g'ridan-to'g'ri berish mumkin: fetch(url, { headers: sarlavhalar }). Oddiy obyekt ham ishlaydi — fetch uni o'zi Headers ga aylantiradi.

3.2 Qiymatlar cheklovi

Sarlavha nomi va qiymati — faqat lotin harflari va oddiy belgilar. Sababi tarixiy: HTTP sarlavhalari ISO-8859-1 (Latin-1) kodlashida yuboriladi. Kodlash (encoding) — har belgiga raqam beradigan jadval. Latin-1 jadvalida atigi 256 ta belgi bor, demak har belgining raqami 255 dan oshmaydi. O'zbekcha ʻ belgisi bilan sinaymiz:

js
const sarlavhalar = new Headers({ "X-Ism": "Gʻani" });

Node 24 da:

text
TypeError: Cannot convert argument to a ByteString because the character at index 1 has a value of 699 which is greater than 255.

Tarjimasi: "Argumentni bayt satriga aylantirib bo'lmadi: 1-o'rindagi belgining qiymati 699, bu 255 dan katta." ʻ belgisining raqami — 699. Chrome qisqaroq aytadi: String contains non ISO-8859-1 code point — "satrda ISO-8859-1 da yo'q belgi bor". Kursda nega oddiy apostrof ' ishlatishimizning yana bir sababi.

Ism, izoh kabi har qanday matnni sarlavhada emas, tanada yuboring. Sarlavhada albatta kerak bo'lsa — encodeURIComponent("Gʻani") bilan kodlang (URL va URLSearchParams).

Nom ichida bo'sh joy ("Ism Familiya") yoki qiymat ichida yangi qator ham xato beradi. Yangi qator bilan hujumchi so'rovga o'z sarlavhasini "ulab" yuborishi mumkin edi — Headers buni oldindan to'sadi.

3.3 Javob sarlavhalari: brauzer hammasini ko'rsatmaydi

Javobning ham headers i bor. Mashq API'si har javobga X-RateLimit-Limit (daqiqalik chegara) sarlavhasini qo'shadi. Node'da o'qiymiz:

js
async function chegarani() {
  const url = "https://ilmhamroh.uz/api/mashq/menyu?sahifa=1&hajm=2";
  const javob = await fetch(url);
  console.log(javob.headers.get("X-Jami"));
  console.log(javob.headers.get("X-RateLimit-Limit"));
}

chegarani();

Konsolda:

text
4
120

Endi xuddi shu kodni brauzerda — natija oynasida ishga tushiramiz. Qaysi sarlavhalarni ko'ramiz?

html
<p>Konsolga qarang.</p>
<script>
  async function sarlavhalarniKor() {
    const url =
      "https://ilmhamroh.uz/api/mashq/menyu?sahifa=1&hajm=2";
    const javob = await fetch(url);
    console.log([...javob.headers.keys()].join(", "));
    console.log("X-Jami:", javob.headers.get("X-Jami"));
    console.log("Limit:", javob.headers.get("X-RateLimit-Limit"));
  }
  sarlavhalarniKor();
</script>

Konsolda:

text
cache-control, content-length, content-type, x-jami, x-sorov-id
X-Jami: 4
Limit: null

Brauzerda X-RateLimit-Limit — null, garchi server uni yuborgan bo'lsa ham. DevTools → Network'da u ko'rinadi, lekin JavaScript'ga berilmaydi. Sabab — CORS: boshqa origin'dan kelgan javobning faqat "xavfsiz" sarlavhalari (Content-Type, Cache-Control, Content-Length ...) va server ruxsat bergan sarlavhalar (X-Jami, X-Sorov-Id) ochiladi. Ruxsat Access-Control-Expose-Headers sarlavhasida keladi. Batafsil — keyingi darsda, CORS mijoz tomondan.

Maslahat: Set-Cookie sarlavhasi brauzerda JavaScript'ga umuman berilmaydi — cookie'ni brauzer o'zi boshqaradi. Node'da esa server bir nechta cookie yuborsa, ularni massiv qilib olish uchun headers.getSetCookie() bor.

Tekshirib ko'ring: h.set("X-A", "1"); h.append("x-a", "2"); h.get("X-A") nima qaytaradi?

Javob

"1, 2". X-A va x-a — bitta sarlavha (harf katta-kichikligi ahamiyatsiz). set qiymatni 1 qildi, append esa 2 ni vergul bilan qo'shdi.

4. Request — so'rov obyekti

4.1 Yasash va ishlatish

new Request(url, sozlamalar) — fetch ning argumentlari bilan aynan bir xil. Uni yasab, keyin fetch ga berasiz:

js
const sorov = new Request("https://ilmhamroh.uz/api/mashq/aks", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ taom: "Osh" }),
});

console.log(sorov.method, sorov.url);
const { cache, credentials, mode, redirect } = sorov;
console.log(cache, credentials, mode, redirect);

Konsolda:

text
POST https://ilmhamroh.uz/api/mashq/aks
default same-origin cors follow

Ikkinchi qator — biz bermagan sozlamalarning standart qiymatlari. Ularni shu darsning "Opsiyalar" bo'limida birma-bir ko'ramiz.

Request qachon kerak? Asosan ikki joyda: so'rovni bir joyda yasab, boshqa joyda yuborish kerak bo'lganda (API klient qatlami) va Service Worker'da. Service Worker — sahifa bilan server orasida turadigan alohida skript; u sahifaning har bir so'rovini Request obyekti sifatida ushlaydi. Uni 13-qismda o'rganamiz (Service Worker), hozir bilish shart emas. Kundalik kodda fetch(url, sozlamalar) yetarli.

4.2 Tanali so'rov — bir martalik

Tanasi bor Request ni ikki marta yuborib bo'lmaydi. Tana quvurdagi suvga o'xshaydi: u birinchi fetch da "oqib ketadi":

js
async function ikkiMarta() {
  const sorov = new Request("https://ilmhamroh.uz/api/mashq/aks", {
    method: "POST",
    body: "osh",
  });
  const birinchi = await fetch(sorov);
  console.log(birinchi.status, sorov.bodyUsed);
  try {
    await fetch(sorov);
  } catch (xato) {
    console.log(xato.message);
  }
}

ikkiMarta();

Konsolda:

text
200 true
Cannot construct a Request with a Request object that has already been used.

Tarjimasi: "Allaqachon ishlatilgan Request obyektidan yangi so'rov yasab bo'lmaydi." bodyUsed — true: tana ishlatildi. Yechim: yuborishdan oldin nusxa oling — fetch(sorov.clone()). Yoki eskisidan yangisini yasang: new Request(sorov, { method: "PUT" }) — hamma sozlama ko'chadi, faqat ko'rsatganingiz o'zgaradi.

5. Response — javob obyekti

5.1 Qo'shimcha xususiyatlar

fetch asoslari da status, ok, headers, url ni ko'rdik. Yana uchtasi:

Xususiyat Nima
redirected javob yo'naltirishdan keyin keldimi (true/false)
bodyUsed tana allaqachon o'qilganmi
type javob turi: basic, cors, opaque ...

type — brauzer javobni qanchalik "ochib" berganini aytadi. opaque so'zi inglizchada "xira, ichi ko'rinmaydigan" degani:

type Qachon Nima o'qiladi
basic o'z origin'ingizdan hamma narsa (Set-Cookie dan tashqari)
cors boshqa origin, CORS ruxsati bilan tana va ruxsat berilgan sarlavhalar
opaque mode: "no-cors" hech narsa: status 0, tana bo'sh
opaqueredirect redirect: "manual" hech narsa, status 0

Natija oynasida mashq API'sidan kelgan javob — cors: u boshqa origin'dan, ruxsat bilan keldi. Node'da esa har doim basic — Node'da CORS yo'q.

5.2 Tanani o'qish usullari

Usul Natija
json() obyekt / massiv
text() satr
blob() Blob (fayl ko'rinishidagi ma'lumot)
arrayBuffer() xom baytlar xotirasi
bytes() Uint8Array — baytlar massivi

bytes() eng yangisi: 2025-yil yanvaridan beri hamma asosiy brauzerda (Baseline). Baytlar bilan File va Blob va Streams API darslarida ishlaymiz. Usul qaysi bo'lmasin — tana faqat bir marta o'qiladi.

5.3 clone() — tanani ikki marta o'qish

Sardorning ikkinchi savoli: javobni logga yozish va ishlatish. Yechim — clone(): javobning nusxasi, o'z tanasi bilan:

js
async function logBilan() {
  const javob = await fetch("https://ilmhamroh.uz/api/mashq/menyu/2");
  const nusxa = javob.clone();

  console.log("Log:", await nusxa.text());
  const taom = await javob.json();
  console.log(taom.nom, taom.narx);
  console.log(javob.bodyUsed, nusxa.bodyUsed);
}

logBilan();

Konsolda:

text
Log: {"id":2,"nom":"Lag'mon","narx":28000,"turkum":"taom"}
Lag'mon 28000
true true

clone() ni tana o'qilishidan oldin chaqiring — keyin kech bo'ladi. Ikkala nusxa ham bir xil tanani alohida o'qiydi.

5.4 O'z javobingizni yasash

Response ni serversiz ham yasash mumkin. Bu testlar uchun juda qulay — "soxta server javobi":

js
async function soxtaJavob() {
  const javob = Response.json({ nom: "Osh" }, { status: 201 });
  console.log(javob.status, javob.ok);
  console.log(javob.headers.get("content-type"));
  console.log(await javob.json());

  const topilmadi = new Response("Topilmadi", { status: 404 });
  console.log(topilmadi.ok, await topilmadi.text());
}

soxtaJavob();

Konsolda:

text
201 true
application/json
{ nom: 'Osh' }
false Topilmadi

Response.json(malumot, sozlamalar) — obyektni JSON qilib, Content-Type ni ham qo'yadi. U 2023-yildan beri hamma brauzerda bor. new Response(tana, sozlamalar) — istalgan tana bilan. 3-mashqda shu bilan fetch siz test yozasiz. Service Worker ham oflayn rejimda sahifaga aynan shunday yasalgan javob beradi.

Tekshirib ko'ring: Javobni clone() qilmasdan avval text() bilan logga yozdingiz, keyin json() chaqirdingiz. Nima bo'ladi?

Javob

json() xato tashlaydi: Node'da Body is unusable: Body has already been read, Chrome'da body stream already read. text() tanani allaqachon oxirigacha o'qib bo'lgan. Ikki marta kerak bo'lsa — o'qishdan oldin clone().

6. Opsiyalar — birma-bir

fetch ning ikkinchi argumentidagi sozlamalarni opsiyalar deymiz. method, headers, body ni bilasiz. Qolganlari:

6.1 signal — bekor qilish va vaqt chegarasi

AbortController darsida signal bilan asinxron ishni to'xtatishni o'rgandik. U fetch bilan ham ishlaydi — va aynan fetch uchun eng ko'p ishlatiladi. Server javobni 2 soniya kechiktiradi, biz esa 300 ms kutamiz:

js
async function vaqtChegarasi() {
  const url = "https://ilmhamroh.uz/api/mashq/menyu?kechikish=2000";
  try {
    await fetch(url, { signal: AbortSignal.timeout(300) });
  } catch (xato) {
    console.log(xato.name);
  }
}

vaqtChegarasi();

Konsolda:

text
TimeoutError

Vaqt tugadi — fetch TimeoutError bilan rad etildi. Foydalanuvchi o'zi bekor qilsa (controller.abort()), xato nomi AbortError bo'ladi. Shu ikki nom bilan "vaqt tugadi" va "bekor qilindi" ni farqlaysiz. Xabar matni esa har xil: Node — The operation was aborted due to timeout, Chrome — signal timed out. Shuning uchun message ga emas, name ga tayaning.

Cookie — brauzer saytga avtomatik qo'shib yuboradigan kichik ma'lumot (masalan, "kim kirgan"). credentials buni boshqaradi:

Qiymat Cookie yuboriladi
"same-origin" (standart) faqat o'z origin'ingizga
"include" boshqa origin'ga ham
"omit" hech qachon

Odatda standart qiymat to'g'ri: o'z sayt API'ingizga cookie ketadi, begona saytga — yo'q. "include" frontend app.example.com da, API esa api.example.com da bo'lganda kerak. Lekin unda server ham alohida ruxsat berishi shart. Mashq API'si cookie ishlatmaydi va "include" bilan kelgan so'rovni brauzer bloklaydi — sababini va aniq xato matnini CORS mijoz tomondan darsida ko'ramiz.

6.3 mode — origin qoidasi

Qiymat Ma'nosi
"cors" (standart) boshqa origin'ga ham, CORS qoidasi bilan
"same-origin" faqat o'z origin'ingizga; boshqasiga — xato
"no-cors" yuboradi, lekin javobni yashiradi (opaque)

"no-cors" — CORS xatosini "tuzatish" emas: javob bo'sh keladi. Bu haqda Origin va Same-Origin Policy darsida ogohlantirgan edik; keyingi darsda haqiqiy natijasini ko'ramiz.

6.4 cache — HTTP kesh bilan munosabat

HTTP sarlavhalari darsida brauzer keshini ko'rgan edik: server Cache-Control bilan "buni 1 soat saqla" deydi va brauzer faylni qayta yuklamaydi. cache opsiyasi shu keshga fetch qanday munosabatda bo'lishini aytadi:

Qiymat Nima qiladi
"default" HTTP qoidalari bo'yicha: yangi bo'lsa keshdan, eskirgan bo'lsa server bilan tekshiradi
"no-store" keshga qaramaydi va javobni keshga yozmaydi
"reload" keshga qaramaydi, lekin yangi javobni keshga yozadi
"no-cache" keshdagini ishlatishdan oldin doim server bilan tekshiradi
"force-cache" keshda bo'lsa — eskirgan bo'lsa ham — o'shani oladi

Yana bitta — "only-if-cached": faqat keshdan, tarmoqqa umuman chiqmaydi. U faqat o'z origin'ingiz bilan ishlaydi; boshqa origin'ga Chrome 'only-if-cached' can be set only with 'same-origin' mode xatosini beradi.

Mashq API'si har javobga Cache-Control: no-store qo'yadi — server "hech qachon keshlama" deydi. Shuning uchun u bilan cache opsiyasining farqini ko'rmaysiz. O'z saytingizda DevTools → Network'dagi Size ustuniga qarang: keshdan kelgan javob (disk cache) yoki (memory cache) deb yoziladi.

6.5 redirect — yo'naltirishga ergashish

Server 301 yoki 302 bilan "bu narsa boshqa manzilda" deydi va Location sarlavhasida yangi manzilni beradi (HTTP status kodlari). Mashq API'sida /holat/301 aynan shunday: u /api/mashq/menyu ga yo'naltiradi.

Qiymat Nima qiladi
"follow" (standart) yangi manzilga o'zi boradi
"manual" ergashmaydi
"error" yo'naltirish bo'lsa — tarmoq xatosi

Standart holatda fetch yo'naltirishni sezdirmasdan bajaradi. Buni redirected va url dan bilasiz:

js
async function yonaltirish() {
  const url = "https://ilmhamroh.uz/api/mashq/holat/301";
  const javob = await fetch(url);
  console.log(javob.status, javob.redirected);
  console.log(javob.url);
}

yonaltirish();

Konsolda:

text
200 true
https://ilmhamroh.uz/api/mashq/menyu

Biz /holat/301 ni so'radik, javob esa /menyu dan keldi — status 200, redirected: true. Sardorning to'rtinchi savoliga javob shu.

"manual" da brauzer va Node farq qiladi. Brauzer javobni yashiradi: type: "opaqueredirect", status: 0 — yo'naltirish bo'lganini bilasiz, lekin qayerga ekanini emas. Node esa haqiqiy 301 ni va Location sarlavhasini beradi. "manual" brauzerda kamdan-kam kerak; Service Worker va serverdagi kodda ishlatiladi.

6.6 keepalive — sahifa yopilsa ham

Sardorning uchinchi savoli. Mehmon sahifani yopdi — pagehide hodisasi keldi (Sahifa hayot sikli). Shu paytda yuborilgan oddiy fetch ni brauzer sahifa bilan birga bekor qilishi mumkin. keepalive: true esa brauzerga aytadi: "sahifa yopilsa ham, bu so'rovni oxiriga yetkaz":

js
addEventListener("pagehide", () => {
  fetch("https://ilmhamroh.uz/api/mashq/aks", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ hodisa: "sahifa yopildi" }),
    keepalive: true,
  });
});

Biz buni Chrome 154 da sinadik: sahifadan boshqa manzilga o'tilgandan keyin ham server so'rovni to'liq oldi. Undan oldin brauzer OPTIONS degan qo'shimcha tekshiruv so'rovini ham yubordi — uni keyingi darsda ko'ramiz. Bu so'rovning javobini hech kim o'qimaydi: sahifa allaqachon yo'q. keepalive — "yubor va unut" so'rovlari uchun.

Cheklovi: bir vaqtda yo'ldagi barcha keepalive so'rovlar tanasi jami 64 KB dan oshmasligi kerak. Oshsa, fetch darhol TypeError bilan rad etiladi. Shuning uchun u kichik statistika uchun, katta fayllar uchun emas.

Sahifa hayot sikli darsida "analitikani yuborish uchun fetch ning keepalive opsiyasi yoki navigator.sendBeacon bor" degan edik. Farqi: sendBeacon(url, tana) — faqat POST, sarlavhalarsiz va javobsiz, bitta qator. keepalive li fetch — istalgan metod va sarlavha bilan. keepalive 2024-yil noyabridan beri hamma asosiy brauzerda (Baseline).

6.7 priority — muhimlik darajasi

Sahifa bir vaqtda o'nlab so'rov yuboradi. priority brauzerga qaysi biri muhimroq ekanini aytadi: "high", "low" yoki "auto" (standart). Masalan, foydalanuvchi kutib turgan menyu — "high", orqa fondagi statistika — "low". Bu buyruq emas, maslahat: brauzer uni hisobga oladi, lekin tartibni kafolatlamaydi. 2024-yil oktabridan beri hamma asosiy brauzerda.

6.8 Qolganlari — bir gapda

  • referrer, referrerPolicy — so'rov qaysi sahifadan kelganini (Referer sarlavhasi) qanchalik to'liq aytish. referrerPolicy: "no-referrer" — umuman aytmaslik.
  • integrity — javob baytlarining "barmoq izi" (hash). Server boshqa narsa bersa, fetch rad etadi. Buni 13-qismda, Brauzer xavfsizlik modeli darsida (SRI) ko'ramiz.

Tekshirib ko'ring: Uch vaziyatga qaysi opsiya kerak? (a) Mehmon sahifani yopayotganda "sahifa yopildi" statistikasini yuborish. (b) Server 5 soniyada javob bermasa, kutishni to'xtatish. (c) Sayt example.com da, API api.example.com da, so'rov bilan kirish cookie'si ham borishi kerak.

Javob

(a) keepalive: true — sahifa yopilsa ham so'rov yetib boradi. (b) signal: AbortSignal.timeout(5000) — 5 soniyadan keyin TimeoutError. (c) credentials: "include" — boshqa origin'ga ham cookie ketadi. Lekin buning uchun server ham alohida ruxsat berishi shart, buni keyingi darsda ko'ramiz.

7. Brauzer va Node farqlari

Opsiyalarning ko'pi brauzer tushunchalari: cookie qutisi, HTTP kesh, origin. Node'da ular yo'q. Node 24 bu opsiyalarni qabul qiladi, lekin ko'pini e'tiborsiz qoldiradi — mode: "no-cors" bilan ham u oddiy 200 javobni to'liq beradi:

Brauzer Node 24
CORS, mode tekshiradi yo'q
credentials, cookie cookie qutisi bor cookie avtomatik yuborilmaydi
cache HTTP kesh bor kesh yo'q
Javob sarlavhalari CORS ruxsat berganlari hammasi
redirect: "manual" opaqueredirect, status 0 haqiqiy 301 + Location
statusText HTTP/2 da "" "OK", "Not Found" ...

Shuning uchun bu kursda tarmoq kodi ikki joyda tekshiriladi: ```js bloklar — Node 24 da, brauzerga xos xulq — natija oynasida, haqiqiy Chrome'da.

8. Hujumchi nigohi

1. credentials: "include" ni hamma joyga qo'yish. "Cookie kerak bo'lib qolar" deb Sardor uni barcha so'rovlarga yozdi — begona domenlarga ham. Endi foydalanuvchining cookie'lari (kirish sessiyasi bilan) o'sha serverlarga ham ketadi, ular esa uni o'z loglariga yozishi mumkin. Qarshi chora: include — faqat o'zingizning va ishonchli API'ingizga, aniq kerak bo'lganda.

2. Sarlavhaga foydalanuvchi matnini qo'yish. Agar sarlavhalar qo'lda satr bilan yig'ilsa, foydalanuvchi kiritgan \r\n yangi sarlavha "ulab" yuborishi mumkin edi (header injection). Headers buni invalid header value xatosi bilan to'sadi — shuning uchun sarlavhalarni doim Headers yoki headers obyekti orqali bering. Foydalanuvchi matni esa umuman tanada bo'lgani yaxshi.

9. Ko'p uchraydigan xatolar

9.1 Tanani clone() siz ikki marta o'qish

text() dan keyin json() — xato. Tuzatish: o'qishdan oldin const nusxa = javob.clone().

9.2 Ishlatilgan Request ni qayta yuborish

Cannot construct a Request with a Request object that has already been used. Tuzatish: fetch(sorov.clone()) yoki har safar yangi Request.

9.3 Brauzerda ruxsat berilmagan sarlavhani o'qish

Node'da X-RateLimit-Limit bor, brauzerda — null. Kod "server buzildi" deb o'ylaydi. Tuzatish: kerakli sarlavhani server Access-Control-Expose-Headers ga qo'shishi kerak (CORS mijoz tomondan).

9.4 Sarlavhada lotin bo'lmagan harf

Gʻani, Ғани — TypeError. Tuzatish: matnni tanada yuboring yoki encodeURIComponent bilan kodlang.

9.5 TimeoutError ni xabar matni bilan tanish

xato.message === "signal timed out" — faqat Chrome'da ishlaydi. Tuzatish: xato.name === "TimeoutError".

10. Mashqlar

1-mashq (oson): Umumiy sarlavhalar

Headers obyekti yasang: Accept: application/json va X-Sinov: bahor. Unga X-Sinov ni qish qiymati bilan append qiling va aks ga GET bilan yuboring. Javobdagi sarlavhalar["x-sinov"] ni chiqaring. Ishora: aks X-Sinov sarlavhasini qaytarib beradi.

Yechim
js
async function sinovSarlavhasi() {
  const sarlavhalar = new Headers({
    Accept: "application/json",
    "X-Sinov": "bahor",
  });
  sarlavhalar.append("X-Sinov", "qish");

  const javob = await fetch("https://ilmhamroh.uz/api/mashq/aks", {
    headers: sarlavhalar,
  });
  const aks = await javob.json();
  console.log(aks.sarlavhalar["x-sinov"]);
}

sinovSarlavhasi();

Konsolda:

text
bahor, qish

append ikkinchi qiymatni vergul bilan qo'shdi va server bitta sarlavha sifatida oldi. set ishlatsangiz — faqat qish qolardi.

2-mashq (o'rta): Log yozadigan fetch

logliFetch(url) funksiyasini yozing: u javob statusini va tananing birinchi 30 belgisini [log] 200 {"id":3,... ko'rinishida chiqarsin, keyin tanani JSON qilib qaytarsin. Tana bir marta o'qilishini unutmang. /menyu/3 bilan sinang. Ishora: clone() va satrning slice(0, 30) metodi (Kesish, birlashtirish — massivdagidek, satrda ham bor).

Yechim
js
async function logliFetch(url) {
  const javob = await fetch(url);
  const matn = await javob.clone().text();
  console.log(`[log] ${javob.status} ${matn.slice(0, 30)}`);
  return javob.json();
}

async function sina() {
  const url = "https://ilmhamroh.uz/api/mashq/menyu/3";
  const taom = await logliFetch(url);
  console.log(taom.nom);
}

sina();

Konsolda:

text
[log] 200 {"id":3,"nom":"Manti","narx":3
Manti

javob.clone().text() — nusxaning tanasi o'qildi, asl javobniki esa butun qoldi. Real loyihalarda bunday "log qatlami" API klientga qo'yiladi (API klient qatlami).

3-mashq (qiyin): Tarmoqsiz test

fetch asoslari dagi taomniOl(id) ni o'zgartiring: u fetch funksiyasini ikkinchi parametr sifatida olsin — taomniOl(id, olibKel = fetch). Keyin soxtaFetch yozing: u tarmoqqa chiqmasdan, id 1 bo'lsa Response.json({ id: 1, nom: "Osh" }), aks holda 404 li javob qaytarsin. taomniOl ni ikkala holatda tekshiring. Faylni kurs/mashqlar/11/19-soxta-javob/test.mjs ga saqlang.

Ishora: soxtaFetch — async funksiya, URL oxiridagi raqamni url.endsWith("/1") bilan tekshiring. Response.json ikkinchi argumentida status beriladi.

Yechim
js
async function taomniOl(id, olibKel = fetch) {
  const url = `https://ilmhamroh.uz/api/mashq/menyu/${id}`;
  const javob = await olibKel(url);
  if (!javob.ok) throw new Error(`HTTP ${javob.status}`);
  return javob.json();
}

async function soxtaFetch(url) {
  if (url.endsWith("/1")) return Response.json({ id: 1, nom: "Osh" });
  return Response.json({ xato: "Taom topilmadi" }, { status: 404 });
}

async function testlar() {
  const osh = await taomniOl(1, soxtaFetch);
  console.log("1-test:", osh.nom === "Osh" ? "o'tdi" : "yiqildi");
  try {
    await taomniOl(99, soxtaFetch);
    console.log("2-test: yiqildi");
  } catch (xato) {
    const otdi = xato.message === "HTTP 404";
    console.log("2-test:", otdi ? "o'tdi" : "yiqildi");
  }
}

testlar();

Konsolda:

text
1-test: o'tdi
2-test: o'tdi

Ikkala test ham tarmoqsiz o'tdi — internet bo'lmasa ham, server o'chiq bo'lsa ham. olibKel = fetch — standart qiymat: oddiy ishlatishda haqiqiy fetch, testda — soxtasi. Bu usul bog'liqlikni tashqaridan berish (dependency injection) deyiladi. Testlarni node:test bilan 12-qismda tartibli yozamiz.

bash
git add 11/19-soxta-javob/test.mjs
git commit -m "11/19: taomniOl ni tarmoqsiz sina"

11. Real ishda

  • API klientlar. Axios, ky kabi kutubxonalar va o'z "API klient"ingiz — umumiy Headers, signal bilan vaqt chegarasi, clone() bilan log. Bularni API klient qatlami darsida bitta modulga yig'amiz.
  • Analitika. Google Analytics, Plausible kabi xizmatlar sahifa yopilganda ma'lumotni keepalive yoki sendBeacon bilan yuboradi.
  • Service Worker va PWA. Oflayn rejimda sahifaning Request larini ushlab, keshdan yoki new Response(...) bilan javob berish — Service Worker darsida.
  • Testlar. Response.json bilan soxta javob — frontend testlarining kundalik usuli. React qismlarida MSW kabi kutubxonalar aynan shu Request/Response obyektlari ustiga qurilgan; hozir bilish shart emas.

Xulosa

  • fetch ichida uch obyekt: Request, Response va ikkalasidagi Headers. Uchalasini o'zingiz ham yasay olasiz.
  • Headers: nomlar harf katta-kichikligiga sezgir emas; set almashtiradi, append qo'shadi; qiymat — faqat Latin-1.
  • Tana bir marta o'qiladi: ikki marta kerak bo'lsa — clone(). Tanali Request ham bir martalik.
  • credentials — cookie, mode — origin qoidasi, cache — HTTP kesh, redirect — yo'naltirish, keepalive — sahifa yopilsa ham, priority — muhimlik, signal — bekor qilish.
  • Brauzer boshqa origin javobining faqat ruxsat berilgan sarlavhalarini ko'rsatadi; Node — hammasini.
  • Ko'p opsiyalar brauzer tushunchasi: Node ularni qabul qiladi, lekin e'tiborsiz qoldiradi.

Keyingi dars: CORS mijoz tomondan — brauzer nega ba'zi javoblarni yashiradi: origin, preflight so'rovi, credentials: "include" va CORS xatosini o'qish.

Manbalar

  • MDN: "Headers", "Request", "Response", "RequestInit" (fetch() options) — developer.mozilla.org
  • WHATWG Fetch Standard: "Request class", "Response class", "keepalive" — fetch.spec.whatwg.org
  • web-features (Baseline): fetch-priority (2024-10), keepalive (2024-11), Response.bytes (2025-01), Response.json (2023-09)
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
fetch Request, Response va Headers: so'rov opsiyalari, kesh, cookie va yo'naltirish — IlmHamroh