IlmHamroh
JavaScript Full-stack/25-qism. HTTP, Express va REST API3/51-dars17 daqiqa
Mundarija (25)

Node.js qo'lda routing: URL, query parametrlar, 404 va 405

Qisqacha: Router — metod + yo'l bo'yicha if zanjiri. new URL(req.url, "http://localhost") yo'l (pathname) va query'ni (searchParams) ajratadi. Yo'l parametri (/vazifalar/5 dagi 5) regex guruhi bilan olinadi. Yo'l topilmasa — 404. Yo'l bor, lekin metod yo'q bo'lsa — 405 va Allow sarlavhasida ruxsat etilgan metodlar. Query qiymatini doim tekshiring: noto'g'ri qiymatga 400.

Bu darsda

  • req.url ni URL bilan yo'l va query'ga ajratasiz, uning tuzoqlarini bilasiz.
  • searchParams bilan get, getAll, has ni ishlatib, query qiymatini tekshirasiz.
  • Regex guruhi va URLPattern bilan yo'l parametrini olasiz.
  • 404, 405 va 400 ni to'g'ri ajratib, Allow sarlavhasini qo'yasiz.
  • vazifalar-api ga routing va markaziy xato ishlovchisini qo'shasiz.

Oldin bilishingiz kerak: http.createServer: req va res, URL anatomiyasi, RegExp asoslari.

1. Nega bu kerak?

O'tgan darsda vazifalar-api ga POST /vazifalar yuborganimizda server 404 Not Found dedi. Bu yolg'on: /vazifalar manzili bor, faqat POST metodi hali yo'q. Frontend dasturchi 404 ni ko'rib, "URL'ni xato yozibman" deb soatlab qidiradi. To'g'ri javob — "bu manzil bor, lekin POST'ni qabul qilmaydi, mana qabul qiladiganlari".

Shuning uchun router (yo'naltiruvchi) kerak: kelgan so'rovni metod va yo'l bo'yicha kerakli funksiyaga yuboradigan, topilmasa to'g'ri xato beradigan qism. Express'da u app.get("/vazifalar/:id", …) ko'rinishida. Bugun uni qo'lda yozamiz va ko'rasiz: ichida — oddiy if zanjiri.

O'xshatish: katta binoning qabulxonasi. Mehmon "3-qavat, 305-xona" deydi. Bunday xona yo'q — "topilmadi" (404). Xona bor, lekin u faqat ertalab ishlaydi — "hozir qabul qilmaydi, ertalab keling" (405 + Allow). Qabulxona xodimi — router.

2. req.url dan URL ga

2.1 Nega new URL kerak

req.url — oddiy satr: "/vazifalar?bajarildi=true". Uni split("?") bilan bo'lish mumkin, lekin foiz-kodlash, takror kalitlar, + belgisi — hammasini o'zingiz hal qilishingiz kerak bo'ladi. Buning uchun tayyor vosita bor — URL (URL anatomiyasi, brauzerda ham, Node'da ham bir xil).

Muammo: req.url da domen yo'q, new URL("/vazifalar") esa xato beradi — to'liq manzil kerak. Shuning uchun ikkinchi argument — asos (base):

js
const url = new URL(req.url ?? "/", "http://localhost");

http://localhost — shunchaki to'ldiruvchi. Biz undan faqat pathname va searchParams ni olamiz. ?? "/" — Node turlarida req.url string | undefined, TypeScript shuni talab qiladi.

2.2 pathname qanday ko'rinadi

Bir nechta "qiyin" so'rov yo'li URL dan o'tganda nima bo'ladi? Bu blok saytda jonli ishlaydi:

js
const base = "http://localhost";
const urls = ["/vazifalar/", "/Vazifalar", "/x/../vazifalar",
  "/vazifalar/%37", "//vazifalar/5", "/vazifalar?bajarildi"];
for (const raw of urls) {
  const u = new URL(raw, base);
  console.log(raw.padEnd(22), "→", u.pathname, u.host);
}

Konsolda:

text
/vazifalar/            → /vazifalar/ localhost
/Vazifalar             → /Vazifalar localhost
/x/../vazifalar        → /vazifalar localhost
/vazifalar/%37         → /vazifalar/%37 localhost
//vazifalar/5          → /5 vazifalar
/vazifalar?bajarildi   → /vazifalar localhost

Har qatorning saboqi:

  1. Oxiridagi / saqlanadi: /vazifalar/ va /vazifalar — ikki xil satr. Bizning router ularni farqlaydi (birinchisi 404). Express ham sukut bo'yicha qat'iy emas — buni Express darsida ko'ramiz.
  2. Katta-kichik harf saqlanadi: /Vazifalar — boshqa yo'l.
  3. .. segmentlari hal qilinadi: /x/../vazifalar → /vazifalar. Static fayllar uchun bu muhim himoya qatlami, lekin yagonasi emas (static fayl darsi).
  4. Foiz-kodlash ochilmaydi: %37 — bu 7, lekin pathname da %37 bo'lib qoladi. Bizning \d+ regex uni raqam deb tanimaydi — 404.
  5. Ikki / bilan boshlansa — URL uni "protokolsiz to'liq manzil" deb o'qiydi: vazifalar — host, yo'l — /5. Shuning uchun url.host ga hech qachon ishonmang — u mijoz yozgan satrdan chiqqan. Haqiqiy host kerak bo'lsa — Host sarlavhasi, u ham tekshiriladi (reverse proxy darsi).
  6. Query pathname ga kirmaydi.

3. Query parametrlar

3.1 searchParams

js
const url = new URL(
  "/vazifalar?bajarildi=true&teg=uy&teg=ish&q=non+olish%21",
  "http://localhost",
);
const q = url.searchParams;
console.log(q.get("bajarildi"), q.getAll("teg"));
console.log(q.get("q"), q.get("yoq"));
console.log(q.has("bajarildi"), [...q.keys()]);

Konsolda:

text
true [ 'uy', 'ish' ]
non olish! null
true [ 'bajarildi', 'teg', 'teg', 'q' ]
  • get — birinchi qiymat yoki null. Natija har doim satr: "true", true emas.
  • getAll — hamma takrorlari massivda. Filtrda bir nechta teg kerak bo'lsa shu.
  • + → bo'shliq, %21 → ! — kodlash o'zi ochiladi (pathname'dan farqli!).
  • Yo'q kalit — null. Bo'sh qiymat (?bajarildi=) esa "" — boshqa narsa.

3.2 Qiymatni tekshirish va 400

Query — mijozdan kelgan matn. Undan son yoki mantiqiy qiymat kutsangiz, tekshiring. vazifalar-api da ?bajarildi= faqat true yoki false bo'lishi mumkin:

ts
const b = url.searchParams.get("bajarildi");
let royxat = ombor.royxat();
if (b === "true" || b === "false") {
  royxat = royxat.filter((v) => v.bajarildi === (b === "true"));
} else if (b !== null) {
  throw new HttpXato(400, "bajarildi — true yoki false");
}

Uch holat: parametr yo'q (null) — hammasi; true/false — filtr; boshqa har narsa (ha, 1, TRUE) — 400 Bad Request. Nega jim e'tiborsiz qoldirmaymiz? Mijoz ?bajarildi=ha yozib, hamma vazifani olsa — u filtr ishladi deb o'ylaydi. Xatoni ochiq aytish — yashirin xatodan yaxshi.

Takror kalit (?bajarildi=true&bajarildi=false) — get birinchisini oladi. Biz curl bilan sinadik: javob true filtri bilan keldi. Qat'iyroq API bunday so'rovga ham 400 beradi. Filtr va saralashni to'liq filtrlash darsida quramiz.

Tekshirib ko'ring: new URL("/v?son=05", "http://x").searchParams.get("son") nima qaytaradi — 5, "5" yoki "05"?

Javob

"05" — satr, o'zgartirilmagan holda. URLSearchParams hech qachon songa aylantirmaydi. Son kerak bo'lsa — Number(...) va Number.isInteger bilan o'zingiz tekshirasiz (matn va son).

4. Yo'l parametrlari

4.1 Regex guruhi

/vazifalar/5, /vazifalar/42 — bitta "shablon", o'zgaradigan qismi id. Regex bilan:

ts
const VAZIFA_YOLI = /^\/vazifalar\/(\d+)$/;

const m = VAZIFA_YOLI.exec(url.pathname);
if (m) {
  const id = Number(m[1]);
  // ...
}
  • ^ va $ — butun satr mos kelishi shart. Usiz /eski/vazifalar/5/x ham mos kelardi.
  • (\d+) — bir yoki ko'p raqam, guruh sifatida. m[1] — shu guruh, satr.
  • Number(m[1]) — songa. "007" → 7, shuning uchun /vazifalar/007 ham 7-vazifani beradi.

Juda katta raqam-chi? Number("99999999999999999999") → 100000000000000000000 va bu xavfsiz butun son emas. Bizning omborda bunday id yo'q — natija 404, zarar yo'q. Lekin id ni bazaga uzatadigan joyda Number.isSafeInteger tekshiruvi qo'shiladi.

4.2 Router — jadval sifatida

Express "ichida nima" ekanini ko'rish uchun routerni ma'lumot sifatida yozamiz. Bu toza funksiya — saytda jonli ishlaydi:

js
const routes = [
  { method: "GET", pattern: /^\/vazifalar$/, name: "royxat" },
  { method: "GET", pattern: /^\/vazifalar\/(\d+)$/, name: "bitta" },
  { method: "DELETE", pattern: /^\/vazifalar\/(\d+)$/,
    name: "ochir" },
];

function route(method, path) {
  const samePath = routes.filter((r) => r.pattern.test(path));
  if (samePath.length === 0) return { status: 404 };
  const hit = samePath.find((r) => r.method === method);
  if (!hit) {
    const allow = samePath.map((r) => r.method).join(", ");
    return { status: 405, allow };
  }
  const id = hit.pattern.exec(path)[1];
  return { status: 200, name: hit.name, id };
}

console.log(route("GET", "/vazifalar/5"));
console.log(route("PATCH", "/vazifalar/5"));
console.log(route("GET", "/vazifalar/abc"));
console.log(route("GET", "/vazifalar"));

Konsolda:

text
{ status: 200, name: 'bitta', id: '5' }
{ status: 405, allow: 'GET, DELETE' }
{ status: 404 }
{ status: 200, name: 'royxat', id: undefined }

Algoritm ikki bosqichli:

flowchart TD
  A["so'rov: metod + yo'l"] --> B{"yo'l mos<br/>marshrut bormi?"}
  B -- yo'q --> N["404 Not Found"]
  B -- ha --> C{"metod ham<br/>mosmi?"}
  C -- yo'q --> M["405 + Allow"]
  C -- ha --> H["ishlovchi"]

Diagrammadagi asosiy fikr: 405 ni bilish uchun avval yo'l bo'yicha guruhlash kerak, keyin metod. Faqat metod + yo'l juftini qidirgan router 405 ni bera olmaydi — hamma narsaga 404. Kanon aynan shu muammoni topdi: Express 5 sukut bo'yicha 405 bermaydi, PUT /vazifalar ga 404 qaytaradi. Express'da uni .all() bilan o'zimiz qo'shamiz (Express'ga kirish darsidan boshlab).

4.3 URLPattern

Regex o'qish qiyin. Yangi standart — URLPattern: Express'dagidek :id yozuvi bilan shablon. Node 24 da u global (biz tekshirdik), saytdagi natija oynasida ham ishlaydi:

js
const pattern = new URLPattern({
  pathname: "/vazifalar/:id([0-9]+)",
});

const hit = pattern.exec({ pathname: "/vazifalar/42" });
console.log(hit.pathname.groups); // { id: '42' }
console.log(pattern.test({ pathname: "/vazifalar/abc" })); // false

:id — nomli parametr, ([0-9]+) — unga qo'yilgan cheklov. Natija groups.id da, yana satr. Kanon vazifalar-api regex bilan qoldi — loyiha bir necha darsdan keyin Express'ga o'tadi va u yerda :id yozuvi bor. URLPattern — framework'siz kichik serverlar va Service Worker'lar uchun qulay vosita.

Tekshirib ko'ring: /^\/vazifalar\/(\d+)$/ ga /vazifalar/5/ (oxirida /) mos keladimi?

Javob

Yo'q. $ raqamlardan keyin darhol satr tugashini talab qiladi, / esa ortiqcha. Natija — 404. Oxirgi / ni qabul qilmoqchi bo'lsangiz \/?$ yozasiz, lekin bitta resursning ikki manzili bo'lishi keshlash va SEO uchun yomon — odatda bittasi tanlanadi.

5. 404, 405 va Allow

HTTP standarti (RFC 9110, «405 Method Not Allowed» bandi): 405 javobida server Allow sarlavhasini yuborishi shart — unda shu resurs qabul qiladigan metodlar. Bu frontend dasturchi uchun tayyor hujjat: xatoning o'zi "nima mumkin" deydi.

Holat Kod Misol
Yo'l ham, metod ham bor 200/201/204 GET /vazifalar
Yo'l bor, metod yo'q 405 + Allow PUT /vazifalar
Yo'l yo'q 404 GET /vazifa
Yo'l bor, id li resurs yo'q 404 GET /vazifalar/999
Query noto'g'ri 400 ?bajarildi=ha

E'tibor bering: /vazifalar/999 ham 404, lekin boshqa sabab bilan — marshrut topildi, omborda vazifa topilmadi. Mijoz uchun ikkalasi ham "bunday narsa yo'q". Xato matni farqni aytadi.

HEAD haqida: standartga ko'ra GET ni qabul qiladigan resurs odatda HEAD ni ham qabul qiladi (bir xil sarlavhalar, tanasiz). Bizning prototipda HEAD /vazifalar hozircha 405 oladi. Express esa HEAD ni GET marshrutiga o'zi yo'naltiradi — framework bergan qulayliklardan biri.

6. Markaziy xato ishlovchisi

Har xato joyida json(res, 404, …) va return yozish — takror va unutish xavfi (o'tgan darsdagi "osilib qolgan so'rov"). Kanon boshqa yo'lni tanladi: xato joyida xato tashlanadi, bitta joyda ushlanadi.

src/tana.ts ga (bu fayl keyingi darsda tana o'qishni ham oladi) xato klassi:

ts
export class HttpXato extends Error {
  readonly holat: number;
  constructor(holat: number, xabar: string) {
    super(xabar);
    this.name = "HttpXato";
    this.holat = holat;
  }
}

ilova.ts da so'rov ishlovchisi async funksiya, ustida esa ushlovchi o'ram (kanon kodi):

ts
return (req: IncomingMessage, res: ServerResponse): void => {
  yonalt(req, res).catch((xato: unknown) => {
    if (res.headersSent) {
      res.destroy(); // javob yarmida — boshqa yo'l yo'q
      return;
    }
    if (xato instanceof HttpXato) {
      json(res, xato.holat, { xato: xato.message });
      return;
    }
    console.error(xato);
    json(res, 500, { xato: "Server xatosi" });
  });
};

Uch tarmoq:

  1. Sarlavhalar ketib bo'lgan — status kodni o'zgartirib bo'lmaydi (ERR_HTTP_HEADERS_SENT). Yagona halol yo'l — ulanishni uzish (destroy), shunda mijoz javob buzilganini biladi.
  2. HttpXato — biz kutgan xato: kodi va matni mijozga.
  3. Boshqa har narsa — kutilmagan xato (dasturdagi bug). Mijozga faqat umumiy "Server xatosi" va 500. Tafsilot (console.error) — faqat server logiga.

Bu naqsh — Express'ning global error handler i va Problem Details ning boshlang'ich shakli.

7. Hujumchi nigohi: router'ga hujum

Regex bilan xizmatni to'xtatish (ReDoS). Ba'zi regex'lar "omadsiz" kirishda juda sekin ishlaydi: /^(a+)+$/ ga "aaa…a!" berilsa, dvigatel barcha bo'linish usullarini sinaydi. Biz o'lchadik (Node 24.21.0, band mashina, bitta o'lchov):

text
22 ta "a" + "!" — 27 ms
24 ta "a" + "!" — 112 ms
26 ta "a" + "!" — 481 ms

Har 2 belgi — vaqt taxminan 4 baravar. 40 belgida bu soatlar bo'ladi. Node bitta thread'da ishlaydi — bitta shunday so'rov event loop'ni bloklaydi va butun server to'xtaydi. Himoya: ichma-ich takrorlovchilardan ((…+)+, (…*)*) qoching; marshrut regex'lari ^…$ bilan oddiy bo'lsin. Bizning ^\/vazifalar\/(\d+)$ — chiziqli, xavfsiz.

Parametrlar toshqini. URLSearchParams parametrlar soniga chek qo'ymaydi — biz 5 000 ta parametrli query berdik, hammasi o'qildi. Node'ning eski querystring.parse i esa 1 000 tadan ortiq kalitni tashlab yuboradi. Express 5 query'ni sukut bo'yicha shu bilan o'qiydi — biz tekshirdik: 5 000 dan 1 000 tasi qoldi. qs kutubxonasida ham xuddi shunday 1 000 chegarasi bor. Sabab — hash jadvali darsidagi "hash toshqini" hujumi: bir xil hash'ga tushadigan minglab kalit jadvalni sekinlashtiradi. Bizda query faqat get bilan o'qiladi va URL uzunligi Node'da sarlavha chegarasi (16 KB, o'tgan dars) bilan cheklangan — xavf kichik. Lekin "hammasini obyektga yig'ish" kodini yozsangiz, chekni o'zingiz qo'ying.

Xato matni orqali sizish. Bizning 404 xabarida yo'l qaytariladi: {"xato":"/vazifalar/abc topilmadi"}. Bu zararsiz, chunki faqat mijozning o'z matni. Lekin 500 da xato.message ni qaytarsangiz — fayl yo'llari, SQL, kalit nomlari sizib chiqadi. Shuning uchun 500 — faqat umumiy matn.

8. API qadami: routing

src/ilova.ts — bugungi holat (telefon uchun uzun qatorlar bo'lingan, if lar qavsli). Kanondagi routing, faqat POST va PATCH hali yo'q (ularga tana kerak — keyingi dars). Shuning uchun Allow hozircha qisqaroq:

ts
const VAZIFA_YOLI = /^\/vazifalar\/(\d+)$/;

export function ilovaYarat({ ombor }: Sozlama) {
  // eslint-disable-next-line @typescript-eslint/require-await
  async function yonalt(
    req: IncomingMessage, res: ServerResponse,
  ): Promise<void> {
    const url = new URL(req.url ?? "/", "http://localhost");
    const metod = req.method ?? "GET";

    if (url.pathname === "/vazifalar") {
      if (metod === "GET") {
        const b = url.searchParams.get("bajarildi");
        let royxat = ombor.royxat();
        if (b === "true" || b === "false") {
          royxat = royxat.filter(
            (v) => v.bajarildi === (b === "true"));
        } else if (b !== null) {
          throw new HttpXato(400, "bajarildi — true yoki false");
        }
        json(res, 200, royxat);
        return;
      }
      res.setHeader("Allow", "GET");
      throw new HttpXato(405, `${metod} bu manzilda yo'q`);
    }

    const m = VAZIFA_YOLI.exec(url.pathname);
    if (m) {
      const id = Number(m[1]);
      if (metod === "GET") {
        const v = ombor.ol(id);
        if (!v) {
          throw new HttpXato(404, `Vazifa ${String(id)} topilmadi`);
        }
        json(res, 200, v);
        return;
      }
      if (metod === "DELETE") {
        if (!ombor.ochir(id)) {
          throw new HttpXato(404, `Vazifa ${String(id)} topilmadi`);
        }
        res.writeHead(204).end();
        return;
      }
      res.setHeader("Allow", "GET, DELETE");
      throw new HttpXato(405, `${metod} bu manzilda yo'q`);
    }

    throw new HttpXato(404, `${url.pathname} topilmadi`);
  }

  // ... «Markaziy xato ishlovchisi» dagi o'ram
}

Kodda uch nozik joy:

  • res.setHeader("Allow", …) xato tashlashdan oldin. Ushlovchidagi json → writeHead uni boshqa sarlavhalar bilan birlashtiradi (setHeader va writeHead).
  • DELETE muvaffaqiyatda — 204 No Content: tanasiz. res.writeHead(204).end() — writeHead res ni qaytaradi, shuning uchun zanjir.
  • eslint-disable izohi: async funksiyada await yo'q — strictTypeChecked buni xato deydi (require-await). Keyingi darsda await jsonTana(req) qo'shilgach izoh olib tashlanadi. Lint qoidasini o'chirsangiz, doim sababini yozing.

Ishga tushirib, sinab ko'ramiz (biz ishga tushirdik, Date va Connection qatorlari olib tashlangan). Chiqishda ikki 405 javobining Allow qatorini solishtiring — manzilga qarab ro'yxat har xil:

bash
curl -i -X PUT $A/vazifalar
curl -i -X PATCH $A/vazifalar/7
curl -i "$A/vazifalar?bajarildi=ha"
curl $A/vazifalar/abc
text
HTTP/1.1 405 Method Not Allowed
Allow: GET
Content-Type: application/json; charset=utf-8
Content-Length: 31

{"xato":"PUT bu manzilda yo'q"}

HTTP/1.1 405 Method Not Allowed
Allow: GET, DELETE
Content-Type: application/json; charset=utf-8
Content-Length: 33

{"xato":"PATCH bu manzilda yo'q"}

HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Content-Length: 40

{"xato":"bajarildi — true yoki false"}

{"xato":"/vazifalar/abc topilmadi"}

Nima bo'ldi? /vazifalar faqat GET ni, /vazifalar/7 esa GET va DELETE ni qabul qiladi — server buni o'zi aytdi. ?bajarildi=ha — 400, abc raqam emas — 404. $A — server manzili (A=http://127.0.0.1:4210). Query bor URL'ni qo'shtirnoqqa oling: Git Bash'da & va ? maxsus belgilar. Content-Length: 40 — — (uzun tire) 3 bayt, shuning uchun belgilar sonidan ko'p.

Testlar: test/api.test.ts dagi birinchi testni routing testi bilan almashtiring:

ts
test("routing: 200, 400, 404, 405 + Allow", async () => {
  const r = await fetch(`${asos}/vazifalar?bajarildi=false`);
  assert.equal(r.status, 200);
  assert.deepEqual(await r.json(), []);
  const ha = await fetch(`${asos}/vazifalar?bajarildi=ha`);
  assert.equal(ha.status, 400);
  assert.equal((await fetch(`${asos}/vazifalar/1`)).status, 404);
  assert.equal((await fetch(`${asos}/vazifalar/abc`)).status, 404);
  assert.equal((await fetch(`${asos}/yoq`)).status, 404);
  const put = await fetch(`${asos}/vazifalar`, { method: "PUT" });
  assert.equal(put.status, 405);
  assert.equal(put.headers.get("allow"), "GET");
  const patch = await fetch(`${asos}/vazifalar/1`, {
    method: "PATCH",
  });
  assert.equal(patch.status, 405);
  assert.equal(patch.headers.get("allow"), "GET, DELETE");
});

npm run check (biz ishga tushirdik): tip 0, lint 0, testlar pass 2. Omborda hali vazifa yo'q (yaratish — POST, keyingi dars), shuning uchun GET /vazifalar/1 faqat 404 holatida sinaladi. Hali commit qilmang.

9. Ko'p uchraydigan xatolar

Belgi Sabab Tuzatish
TypeError: Invalid URL new URL(req.url) asossiz ikkinchi argument "http://localhost"
/vazifalar?x=1 404 req.url === "/vazifalar" bilan solishtirish url.pathname ni solishtiring
hamma xatoga 404 faqat metod + yo'l qidiriladi avval yo'l, keyin metod; 405 + Allow
405 da Allow yo'q sarlavha unutilgan setHeader("Allow", …) xatodan oldin
?bajarildi=true ishlamaydi === true (mantiqiy) bilan solishtirish query — doim satr: === "true"
/vazifalar/5x mos keldi regex'da $ yo'q ^…$

Birinchi qatordagi xatoni ko'rish uchun: new URL("/vazifalar") → TypeError: Invalid URL — "noto'g'ri URL": asossiz nisbiy yo'l to'liq manzil emas.

10. Mashqlar

Mashqlar kurs/mashqlar/25/03-routing/ da.

1-mashq (oson): qaysi kod?

Bizning vazifalar-api (bugungi holat) uchun:

  • DELETE /vazifalar —
  • GET /vazifalar/12 (12-vazifa yo'q) —
  • GET /vazifalar?bajarildi=1 —
  • POST /vazifalar/3 javobidagi Allow —
Yechim
  • 405 — /vazifalar bor, DELETE faqat /vazifalar/:id da. Allow: GET.
  • 404 — marshrut topildi, vazifa topilmadi.
  • 400 — faqat true yoki false.
  • GET, DELETE — /vazifalar/:id ning bugungi metodlari (keyingi darsda PATCH qo'shiladi).

2-mashq (o'rta): sahifa raqami

readPage(searchParams) yozing: ?sahifa= bo'lmasa 1 qaytarsin; butun musbat son bo'lsa — o'sha son; aks holda null (server bunga 400 beradi). Ishora: Number(...) va Number.isInteger (matn va son). Sinang: "", "?sahifa=3", "?sahifa=0", "?sahifa=2.5", "?sahifa=abc".

Yechim
js
function readPage(params) {
  const raw = params.get("sahifa");
  if (raw === null) return 1;
  const n = Number(raw);
  return Number.isInteger(n) && n >= 1 ? n : null;
}

for (const q of ["", "?sahifa=3", "?sahifa=0", "?sahifa=2.5",
  "?sahifa=abc"]) {
  console.log(q || "(bo'sh)", readPage(new URLSearchParams(q)));
}

Konsolda:

text
(bo'sh) 1
?sahifa=3 3
?sahifa=0 null
?sahifa=2.5 null
?sahifa=abc null

Diqqat: Number("") — 0, Number(" 3 ") — 3. Shuning uchun ?sahifa= (bo'sh qiymat) bizda null beradi (0 — musbat emas). Sahifalashni to'liq pagination darsida quramiz.

3-mashq (qiyin): ichma-ich resurs

«Router — jadval sifatida» bo'limidagi route ni kengaytiring: marshrutlarga GET /vazifalar/:id/izohlar/:izohId qo'shing va natijada ikkala parametr ham params obyektida qaytsin ({ id, izohId }). Ishora: regex guruhlariga nom bering — (?<id>\d+), natija exec(path).groups da (RegExp).

Yechim
js
const routes = [
  { method: "GET", pattern: /^\/vazifalar\/(?<id>\d+)$/ },
  {
    method: "GET",
    pattern: /^\/vazifalar\/(?<id>\d+)\/izohlar\/(?<izohId>\d+)$/,
  },
];

function route(method, path) {
  const samePath = routes.filter((r) => r.pattern.test(path));
  if (samePath.length === 0) return { status: 404 };
  const hit = samePath.find((r) => r.method === method);
  if (!hit) {
    const allow = samePath.map((r) => r.method).join(", ");
    return { status: 405, allow };
  }
  const params = { ...hit.pattern.exec(path).groups };
  return { status: 200, params };
}

console.log(route("GET", "/vazifalar/5/izohlar/2"));
console.log(route("GET", "/vazifalar/5"));
console.log(route("DELETE", "/vazifalar/5/izohlar/2"));

Konsolda:

text
{ status: 200, params: { id: '5', izohId: '2' } }
{ status: 200, params: { id: '5' } }
{ status: 405, allow: 'GET' }

groups — prototipsiz obyekt, { ...groups } uni oddiy obyektga ko'chiradi. Express'dagi req.params aynan shunday shakl: nomli parametrlar, qiymatlar satr.

4-mashq: API qadami

«API qadami» bo'limidagidek src/tana.ts (HttpXato) va src/ilova.ts ni yangilang, testni almashtiring. npm run check toza bo'lsin; curl bilan 405 + Allow, 400 va 404 ni o'zingiz ko'ring. Commit qilmang.

Yechim

Kutilgan: tip 0, lint 0, pass 2. curl -i -X PUT …/vazifalar → 405 va Allow: GET; curl -i -X PATCH …/vazifalar/7 → Allow: GET, DELETE. Agar lint require-await xatosini bersa — eslint-disable-next-line izohi unutilgan (u keyingi darsgacha kerak).

11. Real ishda

  • Har framework router'i — Express (path-to-regexp), Fastify (radix daraxt — find-my-way), Hono, Next.js — ichida shu darsdagi ikki bosqich: yo'lni topish, metodni tekshirish. Farq — tezlik va qulay yozuv.
  • API gateway va proxy'lar — nginx location bloklari ham yo'l bo'yicha routing.
  • Xavfsizlik auditi — "bu marshrut faqat GET'mi?", "noma'lum metodga nima qaytaradi?" — pentester birinchi tekshiradigan narsalar.
  • Intervyuda: "404 va 405 farqi?", "query va path parametr qachon?", "Express router ichida nima bor?".

Xulosa

  • Router — metod + yo'l bo'yicha if zanjiri; avval yo'l, keyin metod.
  • new URL(req.url, "http://localhost") — pathname (foiz-kodlash ochilmaydi) va searchParams (ochiladi).
  • Query — doim satr yoki null; noto'g'ri qiymatga 400.
  • Yo'l parametri — ^…$ regex guruhi yoki URLPattern (:id).
  • Yo'l yo'q — 404; metod yo'q — 405 + Allow.
  • Xato tashlanadi, bitta joyda ushlanadi: HttpXato → kod va matn, boshqasi → 500 va log.

Keyingi dars: Request body o'qish va hajm cheklovi — POST va PATCH: tanani oqimdan yig'ish, JSON tahlil, 413 va 415.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Node.js qo'lda routing: URL, query parametrlar, 404 va 405 — IlmHamroh