Mundarija (26)
- Bu darsda
- 1. Nega bu kerak?
- 2. Zanjir qanday ishlaydi
- 2.1 O'z modelimiz
- 2.2 Middleware uch ishdan birini qiladi
- 3. Haqiqiy Express: iz bilan
- 3.1 Darajalar
- 3.2 Oddiy yo'l
- 3.3 next('route') va next('router')
- 3.4 Xato yo'li va noma'lum yo'l
- 4. Tartib qoidasi
- 5. Xato middleware: JSON va xavfsiz
- 5.1 Kanondagi xatoIshlovchi
- 5.2 Testlar topgan xato: 416 → 500
- 6. 405 — Express bermaydigan javob
- 7. Hujumchi nigohi
- 8. API qadami: middleware tartibi va xato ishlovchi (holat 13, 4-qism)
- 9. Ko'p uchraydigan xatolar
- 10. Mashqlar
- 1-mashq (oson): to'ldiring
- 2-mashq (o'rta): modelga marshrut qo'shish
- 3-mashq (qiyin): to'liq zanjir Express'da
- 4-mashq: API qadami
- 11. Real ishda
- Xulosa
- Manbalar
Express middleware: next(), app.use, tartib qoidasi, xato middleware va request lifecycle
Qisqacha: Middleware —
(req, res, next)funksiyasi. So'rov ulardan ro'yxat tartibida o'tadi. Har biri uch ishdan birini qiladi: javob beradi,next()bilan keyingisiga uzatadi yokinext(xato)/throwbilan xato zanjiriga o'tkazadi. Tartib hammasini hal qiladi:express.json()marshrutdan keyin qo'yilsa,req.bodybo'sh qoladi. 404 middleware — oxirida. Xato middleware'i — 4 argumentli(xato, req, res, next)va eng oxirida. Express 5asyncishlovchidagithrowni o'zi ushlaydi. Xato bo'lganda oddiy middleware'lar o'tkazib yuboriladi — biz buni iz bilan ko'rdik.
Bu darsda
- Middleware zanjiri qanday ishlashini 20 qatorli o'z modelingiz bilan ko'rasiz.
app.use, yo'l darajasidagi, router va marshrut darajasidagi middleware'larni farqlaysiz.next(),next('route'),next('router')vanext(xato)ning farqini iz bilan ko'rasiz.- JSON 404 va JSON xato ishlovchi yozasiz; body-parser xatolarini (400, 413) ushlaysiz.
- Express bermaydigan 405 ni
.all()bilan qo'shasiz.
Oldin bilishingiz kerak: req obyekti, res obyekti, Express'ga kirish, Error obyekti va xato turlari.
1. Nega bu kerak?
Har so'rov uchun bir xil ishlar bor: logga yozish, tanani o'qish, sarlavhalar qo'yish, so'rov ID'si berish, xatoni JSON'ga aylantirish. Ularni har marshrut ichiga ko'chirib yozsak — 20 ta marshrutda 20 nusxa. Bittasini unutsak — xavfsizlik teshigi.
Middleware bu ishlarni bitta joyga yig'adi va hamma so'rovga qo'llaydi. Express'ning deyarli hammasi middleware: express.json(), express.static(), router ham, hatto marshrut ishlovchisi ham.
O'xshatish: aeroportdagi yo'l. Kirishda pasport tekshiruvi, keyin bagaj, keyin xavfsizlik ramkasi, keyin chiqish eshigi. Har nuqta yo'lovchini o'tkazadi (next()), to'xtatadi (javob) yoki muammo bo'lsa maxsus xonaga yuboradi (xato zanjiri). Tartibni almashtirsangiz — masalan, bagajni samolyotga chiqqandan keyin tekshirsangiz — hammasi buziladi.
sequenceDiagram
participant M as Mijoz
participant L as log middleware
participant J as express.json()
participant R as marshrut
participant X as xato ishlovchi
M->>L: POST /vazifalar
L->>J: next()
J->>R: next() — req.body tayyor
R-->>M: 201 (javob)
Note over R,X: throw bo'lsa — R dan to'g'ri X gaDiagrammadagi pastki izoh — darsning ikkinchi yarmi: xato bo'lganda zanjir boshqa yo'ldan ketadi.
2. Zanjir qanday ishlaydi
2.1 O'z modelimiz
Express ichidagi g'oya bir necha qator. Middleware'lar — massiv. next — "massivdagi keyingisini chaqir". Xato bo'lsa — faqat 4 argumentlilarni. Bu model saytda ham ishlaydi:
// Express'ning zanjir g'oyasi: ro'yxat + next()
function zanjirYarat(qatlamlar) {
return function ishlat(req, res) {
let i = 0;
function next(xato) {
const q = qatlamlar[i++];
if (!q) return console.log("tugadi:", xato ? "500" : "404");
const xatoUchun = q.length === 4; // (xato, req, res, next)
if (xato && !xatoUchun) return next(xato); // o'tkazib yubor
if (!xato && xatoUchun) return next();
try {
xato ? q(xato, req, res, next) : q(req, res, next);
} catch (e) {
next(e);
}
}
next();
};
}
const ishlat = zanjirYarat([
(req, res, next) => { console.log("1 log:", req.url); next(); },
(req, res, next) => {
if (req.url === "/buz") throw new Error("buzildi");
next();
},
(req, res, next) => {
if (req.url === "/salom") return console.log("3 javob: salom");
next();
},
(xato, req, res, next) => console.log("4 xato:", xato.message),
]);
ishlat({ url: "/salom" }, {});
ishlat({ url: "/buz" }, {});
ishlat({ url: "/yoq" }, {});Konsolda:
1 log: /salom
3 javob: salom
1 log: /buz
4 xato: buzildi
1 log: /yoq
tugadi: 404Uch so'rov — uch yo'l:
/salom— 1, 2, 3; uchinchisi javob berdi vanext()chaqirmadi. Zanjir to'xtadi, xato ishlovchiga yetmadi./buz— 2-qatlamthrowqildi. 3-qatlam o'tkazib yuborildi, to'g'ri 4-ga./yoq— hech kim javob bermadi, zanjir oxiri. Express bu yerda o'zining HTML 404 sahifasini beradi (Express'ga kirish).
Express xato ishlovchini argumentlar soni bo'yicha taniydi — q.length === 4. Shuning uchun xato middleware'ida next ishlatilmasa ham, to'rtinchi parametr yozilishi shart.
2.2 Middleware uch ishdan birini qiladi
| Harakat | Natija |
|---|---|
Javob (res.json, res.sendStatus …) |
zanjir to'xtaydi |
next() |
keyingi mos middleware |
next(xato) yoki throw |
keyingi xato middleware |
| Hech narsa | so'rov osilib qoladi |
Oxirgi qator — eng yoqimsiz xato. Logda hech narsa yo'q, mijoz kutaveradi, keyin timeout. Har middleware'da "har yo'l javob yoki next bilan tugaydimi?" deb tekshiring.
Tekshirib ko'ring: Middleware
if (!req.get("x-kalit")) res.status(401).json(...)deb yozilgan, keyinnext(). Kalitsiz so'rovda nima bo'ladi?
Javob
401 javobi yuboriladi, keyin next() ham chaqiriladi — marshrut ishlaydi va ikkinchi javob yozishga uriniadi: ERR_HTTP_HEADERS_SENT (res darsi). Bundan ham yomoni — marshrutdagi amal (masalan o'chirish) bajarilib ketadi. return res.status(401)... kerak.
3. Haqiqiy Express: iz bilan
3.1 Darajalar
Middleware turli joylarga ulanadi:
| Daraja | Qanday | Qachon ishlaydi |
|---|---|---|
| Ilova | app.use(mw) |
hamma so'rovda |
| Yo'l | app.use("/a", mw) |
/a va /a/... da |
| Router | router.use(mw) |
shu routerga kelganda |
| Marshrut | app.get("/b", mw, ishlovchi) |
faqat shu metod va yo'lda |
| Xato | app.use((xato, req, res, next) => …) |
faqat xato bo'lganda |
Kanon tajribasi har bir darajani iz bilan tekshirdi. Ilova tuzilishi (qisqartirilgan):
app.use(log); // 1
app.use("/a", yolMw); // 2
const r = express.Router();
r.use(routerMw); // 3
r.get("/b", marshrutMw, ishlovchi); // 4, 5
r.get("/b", keyingiIshlovchi); // 6
app.use("/a", r);
app.get("/a/b", appIshlovchi); // 7
app.get("/xato", async () => { throw new Error("buzildi"); }); // 8
app.use(oddiyMw); // 9
app.use((err, req, res, next) => …); // 103.2 Oddiy yo'l
Izdagi har qator — bitta qatlam ishlagani; boshidagi raqam yuqoridagi ro'yxatdagi raqam. Qaysi raqamlar yo'q ekaniga ham qarang:
GET /a/b → 200 "b"
1:app.use
2:app.use('/a') req.url=/b baseUrl=/a
3:router.use
4:route mw
5:handler (javob)
5b:res.send() dan keyingi kod ham ishlaydi
finish 200Shu izni so'rov hayoti (request lifecycle) jadvali sifatida o'qiymiz:
| Qadam | Middleware | Natija |
|---|---|---|
| 1 | app.use(log) |
hamma so'rovda ishladi → next() |
| 2 | app.use("/a", yolMw) |
yo'l /a bilan boshlanadi → ishladi, next() |
| 3 | r.use(routerMw) |
so'rov routerga kirdi → next() |
| 4 | marshrutMw |
GET /b ga mos → next() |
| 5 | ishlovchi |
javob berdi (200 "b") — zanjir to'xtadi |
| 6, 7 | keyingiIshlovchi, appIshlovchi |
chaqirilmadi: javob allaqachon ketgan |
| 9, 10 | oddiyMw, xato ishlovchi |
chaqirilmadi |
Nima bo'ldi? So'rov ro'yxatni yuqoridan pastga yurdi va birinchi javob bergan joyda to'xtadi. Yana ikki narsaga qarang. Birinchidan, 2-qatlamda req.url — /b, req.baseUrl — /a. app.use("/a", …) yo'lning boshini "kesib" beradi — ichkaridagi middleware o'zini ildizda deb biladi. Shuning uchun routerni istalgan yo'lga ulash mumkin (Router darsi). Ikkinchidan, 5b — javobdan keyin ham kod ishladi (res darsidagi return saboq).
3.3 next('route') va next('router')
GET /a/b?otkaz=1 → 200 "b2"
1:app.use
2:app.use('/a') req.url=/b?otkaz=1 baseUrl=/a
3:router.use
4:route mw
6:keyingi route (next('route'))
finish 200
GET /a/b?chiq=router → 200 "app"
1:app.use
2:app.use('/a') req.url=/b?chiq=router baseUrl=/a
3:router.use
7:app.get (next('router') dan keyin)
finish 200next('route')— shu marshrutning qolgan ishlovchilarini (5) tashlab, keyingi mos marshrutga (6) o'tadi. Faqat marshrut darajasidagi middleware'da ishlaydi. Misol: "admin bo'lsa — to'liq javob, bo'lmasa — keyingi, qisqa variant".next('router')— butun routerdan chiqib, ilovadagi keyingi mosga (7) o'tadi.
Ikkalasi ham kam ishlatiladi, lekin eski kodda uchraydi va izsiz tushunish qiyin.
3.4 Xato yo'li va noma'lum yo'l
Ikki so'rov: biri throw qiladi, ikkinchisiga hech kim mos kelmaydi. 9-qatlam qaysi izda bor, qaysida yo'q — shunga qarang:
GET /xato → 500 "xato"
1:app.use
8:async handler throw
10:xato mw (4 argument): buzildi
finish 500
GET /yoq → 404 "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n"
1:app.use
9:oddiy mw (xato bo'lsa O'TKAZIB yuboriladi)
finish 404/xato da 9-qatlam yo'q — xato bo'lganda oddiy middleware o'tkazib yuborildi, bizning modeldagidek. Ishlovchi async — Express 5 rad etilgan Promise'ni o'zi ushlab, xato zanjiriga berdi. Express 4 da bu so'rov osilib qolardi (Express 5 darsi). /yoq da hech qaysi marshrut mos kelmadi: 9 ishladi, keyin zanjir tugadi va Express HTML 404 berdi.
4. Tartib qoidasi
Middleware'lar app.use chaqirilgan tartibda ishlaydi. Shundan kelib chiqadigan qoidalar:
- Tana o'qiydiganlar marshrutlardan oldin.
app.post(...)dan keyinapp.use(express.json())— marshrutreq.bodyniundefinedko'radi. - Arzon va umumiylar — boshida: log, so'rov ID, xavfsizlik sarlavhalari. Javob berib yuboradigan erta qatlam keyingilarini ishlatmaydi.
- static — API'dan oldin yoki keyin — loyihaga qarab. Oldin bo'lsa,
public/dagi fayl API yo'lini "yopib" qo'yishi mumkin. Kanonda static birinchi, chunkipublic/da faqatindex.html. - 404 — barcha marshrutlardan keyin. U hamma narsani ushlaydi; o'rtaga qo'ysangiz, keyingi marshrutlar o'lik bo'ladi.
- Xato ishlovchi — eng oxirida. Undan keyingi
app.usega xato yetib bormaydi.
Kanondagi yakuniy ilovaYarat (holat 13) aynan shu tartibda. Sizdagi oraliq faylda app.use("/vazifalar", …) qatori o'rnida hozircha app.route(...) marshrutlari turibdi — ularni keyingi darsda routerga ko'chiramiz:
app.disable("x-powered-by");
app.use(express.static(join(import.meta.dirname, "..", "public")));
app.use(express.json({ limit: "16kb" }));
app.use("/vazifalar", vazifalarRouteri(vazifaXizmati(ombor)));
app.use((req) => {
throw new HttpXato(404, `${req.method} ${req.path} topilmadi`);
});
app.use(xatoIshlovchi);404 middleware javob bermaydi — throw qiladi. Shunda 404 ham xato ishlovchidan o'tadi va hamma xato bir xil JSON shaklida chiqadi. 404 tanasi bitta joyda yaratiladi.
Tekshirib ko'ring: Kimdir
app.use(helmet())ni xato ishlovchidan keyin qo'shdi. Nima bo'ladi?
Javob
Muvaffaqiyatli so'rovlarda helmet umuman ishlamaydi — marshrutlar javob berib, zanjirni to'xtatgan. 404 va xatolarda ham: xato ishlovchi javob beradi va next() chaqirmaydi. Helmet hech qachon chaqirilmaydi, xavfsizlik sarlavhalari yo'q — va bu sezilmaydi. Shuning uchun xavfsizlik middleware'lari ro'yxat boshida (mashhur middleware'lar).
5. Xato middleware: JSON va xavfsiz
5.1 Kanondagi xatoIshlovchi
const xatoIshlovchi: ErrorRequestHandler = (
xato: unknown, _req, res, next,
) => {
if (res.headersSent) {
next(xato); // javob yarmida — Express o'zi ulanishni uzadi
return;
}
if (xato instanceof HttpXato) {
res.status(xato.holat).json({ xato: xato.message });
return;
}
// body-parser xatolari: `type` maydoni bilan (http-errors)
const tur =
typeof xato === "object" && xato !== null && "type" in xato
? xato.type
: undefined;
if (tur === "entity.parse.failed") {
res.status(400).json({ xato: "Tana yaroqli JSON emas" });
return;
}
if (tur === "entity.too.large") {
res.status(413).json({ xato: "Tana 16 KB dan katta" });
return;
}
// Boshqa kutubxonalar (serve-static: 416, 403...) http-errors
// tashlaydi: status + expose
if (
typeof xato === "object" && xato !== null
&& "status" in xato && typeof xato.status === "number"
&& xato.status < 500
&& "expose" in xato && xato.expose === true
&& xato instanceof Error
) {
res.status(xato.status).json({ xato: xato.message });
return;
}
console.error(xato);
res.status(500).json({ xato: "Server xatosi" });
};(Kanon, uzun qatorlar telefon uchun bo'lingan — siz o'tgan darsda ilova.ts ga aynan shuni ko'chirgansiz.) Qatorma-qator:
headersSent— javob yarmida bo'lsa, yangi status yozib bo'lmaydi.next(xato)— Express'ning sukut ishlovchisi ulanishni uzadi (res darsi).HttpXato— bizning xatolarimiz (404, 405, 409, 415, 422): status va xabar to'g'ridan.entity.parse.failed,entity.too.large—express.json()ning xatolari. U ularnitypemaydoni bilan tashlaydi. Usiz buzuq JSON 500 bo'lib qaytardi — aslida mijoz xatosi (400).- 500 — qolgan hamma narsa. Haqiqiy xabar faqat server logiga (
console.error). Mijozga — umumiy matn. res darsida ko'rgan stack trace oqishi shu bilan yopiladi.
xato: unknown — TypeScript'da ushlangan xato turi noma'lum. Shuning uchun har tekshiruv instanceof yoki "type" in xato bilan. Bu Express + TypeScript darsida chuqurroq.
5.2 Testlar topgan xato: 416 → 500
express.static ga o'tgach, kanon testi Range: bytes=99999- so'radi va 416 kutdi. Server 500 qaytardi. Sabab: serve-static noto'g'ri Range'ni next(err) bilan bizga uzatadi. Xato http-errors kutubxonasidan: status: 416, expose: true ("xabarni mijozga ko'rsatish xavfsiz"). Bizning ishlovchi faqat HttpXato ni tanirdi — qolgan hamma narsa 500.
Tuzatish — uchinchi tarmoq: status < 500 va expose === true bo'lgan xatoning statusi va xabari mijozga ketadi. Shu bilan serve-static ning 403 (traversal), 416 va boshqa kutubxonalarning 4xx xatolari to'g'ri chiqadi. Saboq: o'zingiz yozmagan middleware ham next(xato) chaqiradi — xato ishlovchi faqat o'z xato turlaringizni bilishi yetmaydi. Bu tarmoqni Global error handler darsida tartibga solamiz.
6. 405 — Express bermaydigan javob
Express'ga kirish darsida ko'rdik: PUT /vazifalar → HTML 404. Express yo'l bor, lekin metod yo'qligini bilmaydi. Kanon yechimi — har yo'lning oxiriga .all():
// Express metod mos kelmasa 404 beradi — 405 + Allow ni o'zimiz
function metodYoq(allow: string): RequestHandler {
return (req, res) => {
res.set("Allow", allow);
throw new HttpXato(405, `${req.method} bu manzilda yo'q`);
};
}
r.route("/")
.get(royxatIshlovchi)
.post(jsonKerak, yaratIshlovchi)
.all(metodYoq("GET, HEAD, POST"));metodYoq — middleware fabrikasi: parametr oladi va middleware qaytaradi. express.json({ limit }) ham shunday. .all() zanjir oxirida — GET va POST undan oldin ushlanadi, unga faqat qolgan metodlar yetadi.
Kanon jonli tekshiruvi (holat 13):
HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, POST
Content-Type: application/json; charset=utf-8
Content-Length: 31
…
{"xato":"PUT bu manzilda yo'q"}HEAD ro'yxatda: Express uni GET dan o'zi yasaydi. OPTIONS esa CORS preflight uchun keyinroq kerak bo'ladi (mashhur middleware'lar darsi).
7. Hujumchi nigohi
| Zaiflik | Qanday paydo bo'ladi | Himoya |
|---|---|---|
| Stack trace oqishi | xato ishlovchi yo'q yoki xato.message mijozga |
umumiy 500 matni, tafsilot logda |
| Auth tekshiruvi chetlab o'tildi | auth middleware marshrutdan keyin ulangan | himoya middleware'lari — oldin |
return siz javob |
401 dan keyin ham amal bajarildi | return res... yoki throw |
| Osilgan so'rovlar (DoS) | next() ham, javob ham yo'q |
har yo'l tugashini tekshirish, timeout'lar |
| 500 da ichki ma'lumot | res.json({ xato: e.message }) |
faqat HttpXato va expose xabarlari |
Oxirgi qator: bazaning xato xabarida jadval nomlari, ba'zan parol bo'lgan ulanish satri bo'lishi mumkin. Kanon Problem Details darsida buni test bilan tekshiradi: 500 javobida "parol=maxfiy" yo'q, logda bor.
8. API qadami: middleware tartibi va xato ishlovchi (holat 13, 4-qism)
Hali commit qilmang — keyingi darsda. Bugun ham kod o'zgarmaydi — o'tgan darslarda ko'chirgan ilova.ts da bularning hammasi bor:
- «Tartib qoidasi» bo'limidagi tartib:
disable→ static → json → marshrutlar (app.route) → 404 (throw) →xatoIshlovchi. xatoIshlovchi— uch tarmoq (HttpXato, body-parser,http-errors+expose) va 500.metodYoq(allow)—.all()bilan 405.jsonKerak— marshrut darajasida (req darsi).
Kanon jonli tekshiruvidagi xato javoblari endi hammasi JSON:
{"xato":"Tana yaroqli JSON emas"}
{"xato":"Content-Type: application/json bo'lishi kerak"}
{"xato":"matn 1–200 belgi bo'lishi kerak"}
{"xato":"PUT bu manzilda yo'q"}
{"xato":"Tana 16 KB dan katta"}
{"xato":"GET /yoq topilmadi"}Statuslar mos ravishda: 400, 415, 422, 405, 413, 404. Holat 07 da bu javoblarni o'z json() yordamchimiz yozardi. Endi — bitta xato ishlovchi.
9. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
req.body — undefined |
express.json() marshrutdan keyin |
tartib |
| Xato ishlovchi chaqirilmaydi | 3 argumentli | (xato, req, res, next) — to'rttasi |
| Xato ishlovchidan keyin HTML 404 | 404 xato ishlovchidan keyin | 404 → xato ishlovchi |
| So'rov osilib qoladi | next() ham, javob ham yo'q |
har yo'lni tekshiring |
| Buzuq JSON → 500 | body-parser xatosi ushlanmagan | entity.parse.failed → 400 |
| 416 / 403 → 500 | kutubxona xatosi (http-errors) noma'lum |
status < 500 && expose |
PUT → HTML 404 |
Express 405 bermaydi | .all(metodYoq(...)) |
10. Mashqlar
Yechimlar kurs/mashqlar/25/12-middleware/ da.
1-mashq (oson): to'ldiring
- Xato middleware'ining argumentlar soni —
- Joriy marshrutning qolgan ishlovchilarini tashlab keyingi marshrutga o'tish —
next('') - Xato bo'lganda oddiy middleware'lar — yuboriladi
- 404 middleware'ining joyi — barcha marshrutlardan
express.json()buzuq JSON'da beradigan xato turi —entity.parse.
Yechim
- 4 —
(xato, req, res, next); Expresslengthga qaraydi. - route — faqat marshrut darajasidagi middleware'da.
- o'tkazib — iz:
/xatoda 9-qatlam yo'q. - keyin — aks holda keyingi marshrutlar o'lik.
- failed —
entity.parse.failed→ 400;entity.too.large→ 413.
2-mashq (o'rta): modelga marshrut qo'shish
«O'z modelimiz» bo'limidagi zanjirYarat ni kengaytiring: qatlam funksiya yoki { yol, fn } obyekt bo'lishi mumkin. Obyekt bo'lsa — faqat req.url yol bilan boshlanganda ishlaydi (app.use("/a", mw) kabi). Sinang: /admin ga faqat admin qatlami, /salom ga — yo'q. Eslatma: startsWith — satr metodlari.
Yechim
function zanjirYarat(qatlamlar) {
return function ishlat(req) {
let i = 0;
function next(xato) {
const q = qatlamlar[i++];
if (!q) return console.log(" tugadi:", xato ? "500" : "404");
const fn = typeof q === "function" ? q : q.fn;
if (q.yol && !req.url.startsWith(q.yol)) return next(xato);
const xatoUchun = fn.length === 4;
if (xato && !xatoUchun) return next(xato);
if (!xato && xatoUchun) return next();
try {
xato ? fn(xato, req, null, next) : fn(req, null, next);
} catch (e) {
next(e);
}
}
next();
};
}
const ishlat = zanjirYarat([
{ yol: "/admin", fn: (req, res, next) => {
console.log(" admin tekshiruvi");
if (!req.admin) throw new Error("ruxsat yo'q");
next();
} },
(req, res, next) => {
if (req.url === "/salom") return console.log(" javob: salom");
next();
},
(xato, req, res, next) => console.log(" xato:", xato.message),
]);
for (const req of [{ url: "/salom" }, { url: "/admin/panel" }]) {
console.log(req.url);
ishlat(req);
}Konsolda:
/salom
javob: salom
/admin/panel
admin tekshiruvi
xato: ruxsat yo'q/salom admin qatlamiga umuman kirmadi — yo'l mos emas. Haqiqiy Express buni yo'lni "kesib" ham qiladi (req.url=/panel, baseUrl=/admin), bizning model esa faqat tekshiradi.
3-mashq (qiyin): to'liq zanjir Express'da
Express 5.3.0 bilan oltita qismdan iborat ilova yozing. (1) Log middleware: hamma so'rovni res.on("finish") bilan "METOD yo'l → status" ko'rinishida yig'sin. (2) express.json({ limit: "1kb" }). (3) POST /taomlar — 201 va tana. (4) GET /buz — async ishlovchi: throw new Error("baza ulanmadi: parol=maxfiy"). (5) JSON 404. (6) xato ishlovchi: buzuq JSON → 400, katta tana → 413, qolgani → 500 va umumiy matn. Besh so'rovni yuborib, javoblar va logni chiqaring. Eslatma: res.on("finish", fn) — javob to'liq yuborilganda (EventEmitter).
Yechim
import express from "express";
const app = express();
const iz = [];
app.use((req, res, next) => {
res.on("finish", () =>
iz.push(`${req.method} ${req.path} → ${res.statusCode}`));
next();
});
app.use(express.json({ limit: "1kb" }));
app.post("/taomlar", (req, res) => res.status(201).json(req.body));
app.get("/buz", async () => {
throw new Error("baza ulanmadi: parol=maxfiy");
});
app.use((req, res) => {
const xato = `${req.method} ${req.path} topilmadi`;
res.status(404).json({ xato });
});
app.use((xato, req, res, next) => {
if (res.headersSent) return next(xato);
if (xato.type === "entity.parse.failed") {
return res.status(400).json({ xato: "JSON buzuq" });
}
if (xato.type === "entity.too.large") {
return res.status(413).json({ xato: "tana juda katta" });
}
res.status(500).json({ xato: "Server xatosi" }); // ichki xabar yo'q
});
const server = app.listen(0, "127.0.0.1");
await new Promise((ok) => server.once("listening", ok));
const a = `http://127.0.0.1:${server.address().port}`;
const json = (body) => ({ method: "POST",
headers: { "Content-Type": "application/json" }, body });
const katta = JSON.stringify({ nom: "x".repeat(2000) });
const sorovlar = [
["/taomlar", json('{"nom":"osh"}')],
["/taomlar", json("{nom:")],
["/taomlar", json(katta)],
["/buz", undefined],
["/yoq", undefined],
];
for (const [yol, opts] of sorovlar) {
const r = await fetch(a + yol, opts);
console.log(r.status, await r.text());
}
console.log(iz.join("\n"));
server.closeAllConnections();
server.close();Konsolda:
201 {"nom":"osh"}
400 {"xato":"JSON buzuq"}
413 {"xato":"tana juda katta"}
500 {"xato":"Server xatosi"}
404 {"xato":"GET /yoq topilmadi"}
POST /taomlar → 201
POST /taomlar → 400
POST /taomlar → 413
GET /buz → 500
GET /yoq → 404500 javobida parol=maxfiy yo'q. Log middleware'i birinchi turgani uchun hamma so'rovni, jumladan xatolarni ham ko'rdi: finish hodisasi javob qaysi qatlamda yozilganidan qat'i nazar keladi.
4-mashq: API qadami
Ikki tajriba, har biridan keyin asl holiga qaytaring. (1) xatoIshlovchi dan http-errors tarmog'ini (status < 500 && expose) vaqtincha o'chiring va npm test qiling. Qaysi tekshiruv yiqiladi va qanday status keladi? (2) app.use(express.json(...)) qatorini marshrutlardan keyinga ko'chiring. curl yoki fetch bilan POST /vazifalar yuboring. Javob nima va nega? Commit — keyingi darsda.
Yechim
(1) Biz ishga tushirdik: 6 test o'tdi, 1 yiqildi — static testida actual: 500, expected: 416. Aynan kanon testlari topgan xato («Testlar topgan xato: 416 → 500» bo'limi). (2) Marshrut req.body ni undefined ko'radi. yangiVazifaniTekshir(undefined) 422 qaytaradi ("tana — JSON obyekt bo'lishi kerak") — mijoz to'g'ri JSON yuborgan bo'lsa ham. Tartib xatosi jim, xato xabari esa noto'g'ri tomonga ishora qiladi.
11. Real ishda
- Har Express loyihasi — middleware ro'yxati: helmet, cors, so'rov ID, log, body parser, auth, marshrutlar, 404, xato ishlovchi. Tartibni yangi dasturchiga tushuntirish — onboarding'ning bir qismi.
- NestJS ham shu modelda: guard, interceptor, pipe, exception filter — middleware g'oyasining kengaytmasi.
- Bug'larning ko'pi — tartib xatosi: auth'dan oldingi marshrut, body parser'dan oldingi webhook (
express.raw). - Intervyu: "Middleware nima?", "Xato middleware'ini Express qanday taniydi?", "
next('route')nima qiladi?", "Express 4 va 5 da async xato farqi?".
Xulosa
- Middleware —
(req, res, next); javob,next()yokinext(xato)/throw— hech narsa qilmasa, so'rov osiladi. - Tartib =
app.usetartibi: xavfsizlik va body parser — boshida, 404 — marshrutlardan keyin, xato ishlovchi — oxirida. - Xato ishlovchi 4 argumentli; xato bo'lganda oddiy middleware'lar o'tkazib yuboriladi; Express 5 async
throwni o'zi ushlaydi. - Bitta JSON xato ishlovchi: o'z xatolaringiz, body-parser
type,http-errors(status < 500 && expose), qolgani — umumiy 500. - Express 405 bermaydi —
.all(metodYoq("...")).
Keyingi dars: express.Router va qatlamli loyiha tuzilmasi — routerlar, marshrut → xizmat → ombor qatlamlari va holat 13 commit'i.
Manbalar
- Express — "Using middleware", "Writing middleware", "Error handling": https://expressjs.com/en/guide/using-middleware.html (2026-10-24 da ochildi)
- body-parser — xato turlari (
entity.parse.failed,entity.too.large): https://github.com/expressjs/body-parser#errors - http-errors —
status,expose: https://github.com/jshttp/http-errors - Kanon: middleware tajribasi (tartib izlari,
next('route'),next('router'), async xato — Express 5.3.0, Node 24.21.0), holat 13 (ilova.ts,marshrut.ts, 416 → 500 topilmasi, jonli curl). Zanjir modeli va 3-mashq — biz ishga tushirdik.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!