Mundarija (25)
- Bu darsda
- 1. Nega bu kerak?
- 2. req.url dan URL ga
- 2.1 Nega new URL kerak
- 2.2 pathname qanday ko'rinadi
- 3. Query parametrlar
- 3.1 searchParams
- 3.2 Qiymatni tekshirish va 400
- 4. Yo'l parametrlari
- 4.1 Regex guruhi
- 4.2 Router — jadval sifatida
- 4.3 URLPattern
- 5. 404, 405 va Allow
- 6. Markaziy xato ishlovchisi
- 7. Hujumchi nigohi: router'ga hujum
- 8. API qadami: routing
- 9. Ko'p uchraydigan xatolar
- 10. Mashqlar
- 1-mashq (oson): qaysi kod?
- 2-mashq (o'rta): sahifa raqami
- 3-mashq (qiyin): ichma-ich resurs
- 4-mashq: API qadami
- 11. Real ishda
- Xulosa
- Manbalar
Node.js qo'lda routing: URL, query parametrlar, 404 va 405
Qisqacha: Router —
metod + yo'lbo'yichaifzanjiri.new URL(req.url, "http://localhost")yo'l (pathname) va query'ni (searchParams) ajratadi. Yo'l parametri (/vazifalar/5dagi5) regex guruhi bilan olinadi. Yo'l topilmasa — 404. Yo'l bor, lekin metod yo'q bo'lsa — 405 vaAllowsarlavhasida ruxsat etilgan metodlar. Query qiymatini doim tekshiring: noto'g'ri qiymatga 400.
Bu darsda
req.urlniURLbilan yo'l va query'ga ajratasiz, uning tuzoqlarini bilasiz.searchParamsbilanget,getAll,hasni ishlatib, query qiymatini tekshirasiz.- Regex guruhi va
URLPatternbilan yo'l parametrini olasiz. - 404, 405 va 400 ni to'g'ri ajratib,
Allowsarlavhasini qo'yasiz. vazifalar-apiga 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):
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:
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:
/vazifalar/ → /vazifalar/ localhost
/Vazifalar → /Vazifalar localhost
/x/../vazifalar → /vazifalar localhost
/vazifalar/%37 → /vazifalar/%37 localhost
//vazifalar/5 → /5 vazifalar
/vazifalar?bajarildi → /vazifalar localhostHar qatorning saboqi:
- 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. - Katta-kichik harf saqlanadi:
/Vazifalar— boshqa yo'l. ..segmentlari hal qilinadi:/x/../vazifalar→/vazifalar. Static fayllar uchun bu muhim himoya qatlami, lekin yagonasi emas (static fayl darsi).- Foiz-kodlash ochilmaydi:
%37— bu7, lekinpathnameda%37bo'lib qoladi. Bizning\d+regex uni raqam deb tanimaydi — 404. - Ikki
/bilan boshlansa —URLuni "protokolsiz to'liq manzil" deb o'qiydi:vazifalar— host, yo'l —/5. Shuning uchunurl.hostga hech qachon ishonmang — u mijoz yozgan satrdan chiqqan. Haqiqiy host kerak bo'lsa —Hostsarlavhasi, u ham tekshiriladi (reverse proxy darsi). - Query
pathnamega kirmaydi.
3. Query parametrlar
3.1 searchParams
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:
true [ 'uy', 'ish' ]
non olish! null
true [ 'bajarildi', 'teg', 'teg', 'q' ]get— birinchi qiymat yokinull. Natija har doim satr:"true",trueemas.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:
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:
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/xham mos kelardi.(\d+)— bir yoki ko'p raqam, guruh sifatida.m[1]— shu guruh, satr.Number(m[1])— songa."007"→7, shuning uchun/vazifalar/007ham 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:
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:
{ 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:
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:
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):
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:
- 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. HttpXato— biz kutgan xato: kodi va matni mijozga.- 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):
22 ta "a" + "!" — 27 ms
24 ta "a" + "!" — 112 ms
26 ta "a" + "!" — 481 msHar 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:
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. Ushlovchidagijson→writeHeaduni boshqa sarlavhalar bilan birlashtiradi (setHeader va writeHead).DELETEmuvaffaqiyatda — 204 No Content: tanasiz.res.writeHead(204).end()—writeHeadresni qaytaradi, shuning uchun zanjir.eslint-disableizohi:asyncfunksiyadaawaityo'q —strictTypeCheckedbuni xato deydi (require-await). Keyingi darsdaawait 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:
curl -i -X PUT $A/vazifalar
curl -i -X PATCH $A/vazifalar/7
curl -i "$A/vazifalar?bajarildi=ha"
curl $A/vazifalar/abcHTTP/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:
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/3javobidagiAllow—
Yechim
- 405 —
/vazifalarbor,DELETEfaqat/vazifalar/:idda.Allow: GET. - 404 — marshrut topildi, vazifa topilmadi.
- 400 — faqat
trueyokifalse. - GET, DELETE —
/vazifalar/:idning bugungi metodlari (keyingi darsdaPATCHqo'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
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:
(bo'sh) 1
?sahifa=3 3
?sahifa=0 null
?sahifa=2.5 null
?sahifa=abc nullDiqqat: 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
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:
{ 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
locationbloklari 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'lbo'yichaifzanjiri; avval yo'l, keyin metod. new URL(req.url, "http://localhost")—pathname(foiz-kodlash ochilmaydi) vasearchParams(ochiladi).- Query — doim satr yoki
null; noto'g'ri qiymatga 400. - Yo'l parametri —
^…$regex guruhi yokiURLPattern(: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
- RFC 9110 — HTTP Semantics (2022-06): 405 va
Allow(§15.5.6, §10.2.1),HEAD(§9.3.2): https://www.rfc-editor.org/rfc/rfc9110 - WHATWG URL Standard —
URL,URLSearchParams: https://url.spec.whatwg.org/ · URLPattern Standard: https://urlpattern.spec.whatwg.org/ - Node.js 24 hujjati — URL (
URL,URLSearchParams,URLPattern): https://nodejs.org/docs/latest-v24.x/api/url.html - OWASP — Regular expression Denial of Service (ReDoS): https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- Kanon:
vazifalar-apiholat 05 (ilova.tsrouting,HttpXato, ushlovchi o'ram); Express 5 da 405 yo'qligi —QADAMLAR.md(holat 13 topilmasi). Bugungi oraliqilova.ts,curlchiqishlari, testlar, ReDoS o'lchovi va 5 000 parametr — biz ishga tushirdik (Node 24.21.0, Windows 11, 2026-10-24).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!