Mundarija (26)
- Bu darsda
- 1. Nega bu kerak?
- 2. Besh g'isht
- 2.1 Har biri — bitta savol
- 2.2 To'rt daraja
- 2.3 Qaysi darajani tanlash
- 3. Kanon tajribasi: haqiqiy iz
- 3.1 Tajriba sharti
- 3.2 Muvaffaqiyatli so'rov
- 3.3 Pipe xatosi
- 3.4 Guard rad etdi
- 4. Middleware va guard: kim nimani biladi
- 4.1 ExecutionContext
- 4.2 Middleware xatosi qayerga boradi
- 5. JS modelida so'rov yo'li
- 6. Qaysi vazifa — qaysi mexanizm
- 6.1 Bitta so'rovni boshidan oxirigacha kuzatamiz
- 7. Nega loyihaga kirmadi
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): tartibni toping
- 2-mashq (o'rta): interceptor xatoni yutadi
- 3-mashq (qiyin): eng yaqin filter @Catch turi bilan
- 10. Real ishda
- Xulosa
- Manbalar
NestJS request lifecycle: middleware, guard, interceptor, pipe va filter tartibi
Qisqacha: Nest'da so'rov qat'iy tartibda o'tadi: middleware → guard → interceptor (oldin) → pipe → handler → interceptor (keyin) → javob. Har bosqichda tartib "keng → tor": global (avval
APP_*provider'lar, keyinuseGlobal*), keyin controller, keyin route. Interceptor'ning "keyin" qismi teskari tartibda ishlaydi. Xato bo'lsa, interceptor'lar xato tarmog'idan o'tadi va faqat bitta — eng yaqin — exception filter javob beradi. Guard rad etsa, interceptor, pipe va handler umuman ishlamaydi.
Bu darsda
- Nest'ning besh "g'ishti" — middleware, guard, interceptor, pipe, filter — qaysi savolga javob berishini bilasiz.
- So'rovning to'liq yo'lini kanon tajribasining haqiqiy izi bilan o'qiysiz.
- Global, controller va route darajalari qaysi tartibda ishlashini va
APP_GUARDbilanuseGlobalGuardsfarqini tushuntirasiz. - Xato bo'lganda qaysi filter javob berishini oldindan ayta olasiz.
vazifalar-apidagi har vazifa uchun to'g'ri mexanizmni tanlaysiz.
Oldin bilishingiz kerak: Bootstrap: main.ts va ilova sozlamalari, Middleware va request lifecycle, Global error handler, Controller'lar va route dekoratorlari.
O'tgan darsda vazifalar-api to'liq Nest'ga o'tdi. Lekin uning ichi hali 25-qism uslubida: kirish tekshiruvi handler ichida, sarlavhalar @Res({ passthrough: true }) orqali. Keyingi darslarda bular Nest'ning o'z mexanizmlariga ko'chadi. Bu dars — xarita: qaysi mexanizm qachon ishlaydi. Loyihaga kod qo'shilmaydi, faqat tajriba.
1. Nega bu kerak?
25-qismda so'rov hayoti oddiy edi: middleware'lar siz yozgan tartibda ishlardi (Middleware va request lifecycle). app.use(a); app.use(b) — avval a, keyin b. Xato bo'lsa — oxirgi 4 argumentli ishlovchi.
Nest'da qurilish bloklari ko'p: middleware, guard, interceptor, pipe, filter. Har biri global, controller yoki route darajasida qo'yilishi mumkin. Tartibni endi siz emas, freymvork belgilaydi. Uni bilmasangiz, g'alati xatolar chiqadi: "nega mening logim chiqmadi?", "nega pipe guard'dan oldin ishlamadi?", "nega global filtrim javob bermadi?".
O'xshatish: aeroport. Avval bino eshigi (middleware) — hammani kiritadi, sumkani skanerlaydi. Keyin pasport nazorati (guard) — "uchishga ruxsatingiz bormi?". Keyin samolyot ichi (interceptor) — parvoz boshida va oxirida xizmat. Bagaj tartibga solinadi (pipe). Uchishning o'zi — handler. Muammo bo'lsa — navbatchi xodim (filter), lekin faqat eng yaqindagisi.
2. Besh g'isht
2.1 Har biri — bitta savol
| Mexanizm | Savol | Express'dagi o'xshashi |
|---|---|---|
| middleware | "So'rovni oldindan tayyorlash kerakmi?" | app.use(fn) |
| guard (himoyachi) | "Bu so'rov handler'ga o'tsinmi?" | auth middleware, 403 |
| interceptor (ushlab qoluvchi) | "Handler'dan oldin va keyin nima qilay?" | res.on("finish"), javobni o'rash |
| pipe | "Argument to'g'rimi, kerakli turdami?" | Zod tekshir() handler boshida |
| exception filter (xato filtri) | "Xatoni qanday javobga aylantiray?" | 4 argumentli xato ishlovchi |
Ta'riflar:
- Middleware — Express middleware'ining aynan o'zi. U Nest'ni bilmaydi: qaysi controller, qaysi metod ishlashini ko'rmaydi. To'liq — Middleware Nest'da.
- Guard — "ha yoki yo'q" deydigan klass. U qaysi handler chaqirilishini biladi va uning metama'lumotini (masalan
@Rollar("admin")) o'qiy oladi.falseqaytarsa — 403. To'liq — Guard'lar. - Interceptor — handler'ni o'rab oladi: oldin bir narsa qiladi, keyin javobni ko'radi yoki o'zgartiradi. Ichida RxJS oqimi ishlaydi. To'liq — Interceptor'lar va RxJS.
- Pipe — har argumentni handler'ga berishdan oldin tekshiradi yoki o'zgartiradi (
"7"→7). To'liq — Pipe'lar. - Exception filter — o'tgan darsdagi
ProblemDetailsFilter. To'liq — Exception filter'lar.
2.2 To'rt daraja
Middleware'dan boshqa hammasi to'rt joyda qo'yilishi mumkin:
// 1) global, DI orqali — modul provider'i
providers: [{ provide: APP_GUARD, useClass: DiGuard }],
// 2) global, qo'lda — main.ts / ilova.ts da
app.useGlobalGuards(new OddiyGuard());
// 3) controller — klass ustida
@UseGuards(ControllerGuard)
@Controller("t")
class TController {
// 4) route — metod ustida
@UseGuards(RouteGuard)
@Get(":id") ol() { /* … */ }
}Pipe uchun beshinchi joy ham bor — bitta parametr: @Param("id", ParseIntPipe).
APP_GUARD va useGlobalGuards farqi: birinchisi — Nest yaratadigan provider, uning constructor'i boshqa provider'larni (ombor, config) ola oladi. Ikkinchisi — siz new bilan yaratgan tayyor obyekt, DI'dan tashqarida. O'tgan darsdagi new ProblemDetailsFilter(log) — ikkinchi tur. Uni APP_FILTER ga o'tkazish — Global enhancer'lar va bajarilish tartibi darsida.
2.3 Qaysi darajani tanlash
Daraja — "bu qoida qancha yo'lga tegishli" degan savolning javobi:
| Daraja | Qachon | vazifalar-api dan misol |
|---|---|---|
| global | butun ilovaga bitta qoida | Problem Details filtri, auth guard |
| controller | bitta resursning hamma yo'llariga | /eksportlar ga alohida cheklov |
| route | bitta metodga | faqat POST /toplam uchun katta tana |
| parametr (pipe) | bitta argumentga | :id — musbat butun son |
Qoida: qoidani eng tor mos darajaga qo'ying. Hamma narsa global bo'lsa, "bu yo'lga nega bu tekshiruv tushdi?" degan savolga javob topish qiyinlashadi. Hamma narsa route darajasida bo'lsa — takror va unutilgan metodlar paydo bo'ladi. Ikki chekka o'rtasidagi muvozanat — controller.
Bitta darajada bir nechta bo'lsa ham tartib aniq: @UseGuards(A, B) — avval A, keyin B, chapdan o'ngga. A rad etsa, B umuman chaqirilmaydi. Interceptor'larda @UseInterceptors(A, B) — A tashqi qavat: kirishda birinchi, chiqishda oxirgi. Shuning uchun arzon tekshiruvni chapga yozing: masalan, "tana JSON'mi" guard'i qimmat baza so'rovi qiladigan guard'dan oldin.
Interceptor'ni piyozga o'xshatish mumkin. Har qavat handler'ni o'raydi. So'rov tashqaridan ichkariga kiradi — global qavat birinchi. Javob ichkaridan tashqariga chiqadi — global qavat oxirgi. Shuning uchun global interceptor eng aniq vaqtni o'lchaydi: u boshqa hamma qavatlarni o'z ichiga oladi.
3. Kanon tajribasi: haqiqiy iz
3.1 Tajriba sharti
Kanon har darajaga har mexanizmdan bittadan qo'ydi. Har biri ishga tushganda o'z nomini ro'yxatga yozadi (yoz(...)). Kod qisqartirilgan:
const guard = (nom: string, ruxsat = true): CanActivate => ({
canActivate: () => {
yoz(`guard: ${nom}`);
return ruxsat;
},
});
const interceptor = (nom: string): NestInterceptor => ({
intercept: (_c, next) => {
yoz(`interceptor (oldin): ${nom}`);
return next.handle().pipe(tap({
next: () => { yoz(`interceptor (keyin): ${nom}`); },
error: () => { yoz(`interceptor (xato): ${nom}`); },
}));
},
});
@Controller("t")
@UseGuards(guard("controller"))
@UseInterceptors(interceptor("controller"))
@UsePipes(pipe("controller"))
@UseFilters(new Filtr("controller"))
class TController {
@Get(":id")
@UseGuards(guard("route"))
@UseInterceptors(interceptor("route"))
@UsePipes(pipe("route"))
@UseFilters(new Filtr("route"))
ol(@Param("id", yiqiluvchiPipe) id: string) {
yoz("HANDLER");
if (id === "boom") throw new Error("handler yiqildi");
return { id };
}
@Post()
@UseGuards(guard("route (rad)", false))
yoz(@Body() b: unknown) { /* … */ }
}Modulda APP_GUARD, APP_INTERCEPTOR, APP_PIPE, APP_FILTER, configure() da modul middleware'i; bootstrap'da app.use, useGlobalGuards, useGlobalInterceptors, useGlobalPipes, useGlobalFilters. yiqiluvchiPipe — param pipe: "xato" kelsa xato tashlaydi. Filtr har xatoga 418 va {"filtr": "<nomi>"} qaytaradi — qaysi filtr ishlaganini ko'rish uchun. Tajriba Vitest muhitida (Vite) yurgizilgan.
3.2 Muvaffaqiyatli so'rov
Birinchi so'rov hech qayerda yiqilmaydi. Izdagi har qator — bitta mexanizm ishga tushgan lahza. Qatorlarning tartibiga qarang, raqamlar shuning uchun qo'yilgan:
1) muvaffaqiyatli GET /t/5 → 200 {"id":"5"}
1. middleware: global (app.use)
2. middleware: modul (MiddlewareConsumer)
3. guard: global (APP_GUARD)
4. guard: global (useGlobalGuards)
5. guard: controller
6. guard: route
7. interceptor (oldin): global (APP_INTERCEPTOR)
8. interceptor (oldin): global (useGlobalInterceptors)
9. interceptor (oldin): controller
10. interceptor (oldin): route
11. pipe: global (APP_PIPE) (param:id)
12. pipe: global (useGlobalPipes) (param:id)
13. pipe: controller (param:id)
14. pipe: route (param:id)
15. pipe: route param (yiqiladi)
16. HANDLER
17. interceptor (keyin): route
18. interceptor (keyin): controller
19. interceptor (keyin): global (useGlobalInterceptors)
20. interceptor (keyin): global (APP_INTERCEPTOR)
21. javob ketdi: 20021 qatorni guruhlab o'qing:
- 1–2. Avval middleware'lar:
app.usebilan qo'yilgani, keyin modul middleware'i. - 3–6. Guard'lar: global → controller → route. Ikki global guard'dan avval
APP_GUARD(DI orqali), keyinuseGlobalGuards. - 7–10. Interceptor'larning "oldin" qismi — xuddi shu tartibda.
- 11–15. Pipe'lar: global → controller → route → parametr.
(param:id)— pipe qaysi argument ustida ishlayotgani. 15-qatordagi pipe nomi "yiqiladi", lekin bu so'rovdaid—"5", u o'tkazib yubordi. - 16. Handler.
- 17–20. Interceptor'larning "keyin" qismi — teskari: route → controller → global. Eng ichki o'rovchi birinchi ko'radi.
- 21. Javob ketdi.
Kanonning bitta topilmasi 3–4 va 7–8 qatorlarda: DI bilan qo'yilgan global (APP_*) enhancer useGlobal* dan oldin ishlaydi.
sequenceDiagram
participant M as Middleware
participant G as Guard
participant I as Interceptor
participant P as Pipe
participant H as Handler
M->>G: global, modul
G->>I: global, controller, route
I->>P: oldin: global → route
P->>H: global → param
H-->>I: natija
I-->>M: keyin: route → globalDiagrammadagi qaytuvchi strelkalarga qarang: javob interceptor'lardan teskari tartibda o'tadi. Kirishda global birinchi, chiqishda — oxirgi.
3.3 Pipe xatosi
Ikkinchi so'rovda id — "xato", parametr pipe'i uni rad etadi. Endi HANDLER qatori bormi-yo'qligiga va interceptor qatorlarida qaysi so'z turganiga qarang:
2) pipe xatosi GET /t/xato → 418 {"filtr":"route"}
…
14. pipe: route (param:id)
15. pipe: route param (yiqiladi)
16. interceptor (xato): route
17. interceptor (xato): controller
18. interceptor (xato): global (useGlobalInterceptors)
19. interceptor (xato): global (APP_INTERCEPTOR)
20. filter: route ← pipe rad etdi
21. javob ketdi: 418(1–13 qatorlar muvaffaqiyatli so'rovdagidek — qisqartirdik.)
Uch narsa. Birinchidan, HANDLER yo'q — pipe rad etdi, handler chaqirilmadi. Ikkinchidan, interceptor'lar xato tarmog'idan o'tdi (error callback'i), yana teskari tartibda. Demak pipe xatosi interceptor'lar "ichida" sodir bo'ladi — interceptor uni ko'radi va xohlasa o'zgartira oladi. Uchinchidan, faqat bitta filter ishladi — route. Controller va global filtrlar ham bor edi, lekin ular ishlamadi. Nest eng yaqin filtrni tanlaydi va to'xtaydi.
Handler xatosi (GET /t/boom) ham xuddi shunday: HANDLER dan keyin interceptor'larning xato tarmog'i va filter: route ← handler yiqildi.
3.4 Guard rad etdi
To'rtinchi so'rov POST /t ga boradi. U yerdagi route guard ataylab false qaytaradi. Iz qancha qisqarganiga qarang:
4) guard rad etdi POST /t → 418 {"filtr":"controller"}
1. middleware: global (app.use)
2. middleware: modul (MiddlewareConsumer)
3. guard: global (APP_GUARD)
4. guard: global (useGlobalGuards)
5. guard: controller
6. guard: route (rad)
7. filter: controller ← Forbidden resource
8. javob ketdi: 418Atigi 8 qator. Route guard false qaytardi va zanjir shu yerda uzildi: interceptor ham, pipe ham, handler ham yo'q. Nest false ni ForbiddenException("Forbidden resource") ga aylantirdi — "Taqiqlangan resurs". Javob bergan filter — controller: POST metodida route filtri yo'q edi, eng yaqini controller'niki.
Bu tartibning ma'nosi bor: ruxsati yo'q so'rov uchun tanani tekshirish (pipe) yoki vaqtni o'lchash (interceptor) — behuda ish. Guard ularni oldindan to'xtatadi.
Tekshirib ko'ring: Global interceptor so'rov vaqtini o'lchaydi va logga yozadi. Guard so'rovni rad etdi. Bu so'rov logda bormi?
Javob
Yo'q. Guard interceptor'dan oldin ishlaydi — rad etilgan so'rov interceptor'gacha yetmaydi (tajribadagi 4-holat: 8 qatorda interceptor yo'q). Har so'rovni loglash kerak bo'lsa — middleware ishlating: u guard'dan oldin. vazifalar-api da so'rov logi shuning uchun app.use(sorovLogi(log)) — middleware.
4. Middleware va guard: kim nimani biladi
4.1 ExecutionContext
Middleware va guard ikkalasi ham handler'dan oldin ishlaydi. Unda farq nima? Farq — ko'rish doirasi. Demo loyihada ikkalasi bir so'rov haqida nima bilishini chiqardik (biz ishga tushirdik: NestJS 12.2.0, Node 24.21.0):
class KimGuard implements CanActivate {
canActivate(ctx: ExecutionContext) {
const req = ctx.switchToHttp().getRequest<Request>();
console.log(
`guard: ${ctx.getType()} ${ctx.getClass().name}.` +
`${ctx.getHandler().name} (${req.method} ${req.url})`,
);
return true;
}
}
app.use((q: Request, _s: Response, n: NextFunction) => {
console.log(
`middleware: ${q.method} ${q.url}, route: ${String(q.route)}`,
);
n();
});GET /vazifalar/7 so'rovi:
middleware: GET /vazifalar/7, route: undefined
guard: http VazifalarController.ol (GET /vazifalar/7)Middleware faqat URL'ni ko'rdi: qaysi marshrut ishlashi hali noma'lum (route: undefined). Guard esa aniq biladi: kontekst turi http, klass VazifalarController, metod ol. Bu ma'lumotni ExecutionContext (bajarilish konteksti) beradi — guard, interceptor va filter oladigan obyekt. getHandler() va getClass() orqali ular metod va klass ustidagi dekoratorlarni o'qiy oladi: "bu yo'l ochiqmi?", "qaysi rol kerak?". Bu — Reflector va DiscoveryService darsining mavzusi.
ctx.getType() — http, rpc (mikroservis) yoki ws (WebSocket). Bitta guard uchala transportda ishlashi mumkin, shuning uchun so'rov switchToHttp() orqali olinadi — o'tgan darsdagi filtrdagi host.switchToHttp() ham shu sababdan.
4.2 Middleware xatosi qayerga boradi
Middleware Nest'ni bilmasa, uning xatosini kim ushlaydi? Demo: app.use middleware'i /a da, modul middleware'i (MiddlewareConsumer) /b da xato tashlaydi; global filtr 418 va xabarni qaytaradi:
GET /a → 418 {"filtr":"global","xabar":"app.use xatosi"}
GET /b → 418 {"filtr":"global","xabar":"modul middleware xatosi"}
GET /c → 200 {"handler":true}Ikkala xato ham global filtrga yetdi. Nest Express'ning xato yo'liga o'z ishlovchisini ulaydi, shuning uchun app.use dagi xato ham filtrdan o'tadi. Lekin faqat global filtrdan: controller va route filtrlari middleware xatosini ko'rmaydi — o'sha paytda marshrut hali tanlanmagan. O'tgan darsdagi tanaXatosi topilmasi shu yo'lda sodir bo'lgan: express.json xatosi global filtrga yetguncha Nest uni "xaritalab" ulgurgan edi.
5. JS modelida so'rov yo'li
Tartibni kichik modelda takrorlaymiz — brauzerda ishlaydi. Har bosqich to'rt darajada (APP, global, controller, route); int> — interceptor oldin, int< — keyin, int! — xato tarmog'i:
const DARAJA = ["APP", "global", "controller", "route"];
function sorov(nom, { guardRad, pipeXato, handlerXato, filtrlar }) {
const iz = [];
try {
iz.push("mw:global", "mw:modul");
for (const d of DARAJA) {
iz.push(`guard:${d}`);
if (guardRad && d === "route") throw new Error("Forbidden");
}
for (const d of DARAJA) iz.push(`int>${d}`);
try {
for (const d of DARAJA) iz.push(`pipe:${d}`);
if (pipeXato) throw new Error("pipe rad etdi");
iz.push("HANDLER");
if (handlerXato) throw new Error("handler yiqildi");
for (const d of DARAJA.toReversed()) iz.push(`int<${d}`);
} catch (x) {
for (const d of DARAJA.toReversed()) iz.push(`int!${d}`);
throw x;
}
} catch (x) {
// faqat bitta filter — eng yaqini (route → controller → global)
const f = ["route", "controller", "global"]
.find((d) => filtrlar.includes(d));
iz.push(`filter:${f} ← ${x.message}`);
}
console.log(`${nom}: ${iz.join(" ")}`);
}
const filtrlar = ["route", "controller", "global"];
sorov("1", { filtrlar });
sorov("2", { pipeXato: true, filtrlar });
sorov("4", { guardRad: true, filtrlar: ["controller", "global"] });Konsolda:
1: mw:global mw:modul guard:APP guard:global guard:controller guard:route int>APP int>global int>controller int>route pipe:APP pipe:global pipe:controller pipe:route HANDLER int<route int<controller int<global int<APP
2: mw:global mw:modul guard:APP guard:global guard:controller guard:route int>APP int>global int>controller int>route pipe:APP pipe:global pipe:controller pipe:route int!route int!controller int!global int!APP filter:route ← pipe rad etdi
4: mw:global mw:modul guard:APP guard:global guard:controller guard:route filter:controller ← ForbiddenUch qator — kanon izining qisqa shakli. Modelning tuzilishiga qarang: interceptor'lar ichki try ni o'raydi, shuning uchun pipe va handler xatosini ko'radi; guard xatosi esa tashqi try da — interceptor'ga yetmaydi. Haqiqiy Nest'da ham shunday: guard'lar interceptor zanjiridan tashqarida.
Model soddalashtirilgan: haqiqiy Nest'da interceptor xatoni "yutib" boshqa javob qaytara oladi, filter esa xato turiga qarab tanlanadi (@Catch(HttpException) faqat shu turni ushlaydi). toReversed — massivni teskari nusxalaydi (massiv saralash).
6. Qaysi vazifa — qaysi mexanizm
vazifalar-api dagi ishlarni joyiga qo'yamiz. Hozir ularning ko'pi 25-qism uslubida turibdi, keyingi darslarda shu jadval bo'yicha ko'chadi:
| Vazifa | Mexanizm | Nega aynan u |
|---|---|---|
sorovId, so'rov logi, helmet, CORS |
middleware | hamma so'rovga, guard'dan oldin |
| JSON tana o'qish (16 KB) | middleware | handler'ni bilish shart emas |
| 415 — tana JSON emas | guard | handler'ga o'tsinmi? — ha/yo'q |
| Auth (28-qism) | guard | metama'lumot (@Ochiq) kerak |
Zod bilan body/params tekshiruvi |
pipe | har argument alohida |
ETag, Cache-Control, vaqt o'lchash |
interceptor | javobni ko'rish kerak |
| Problem Details | filter | xatoni javobga aylantirish |
Ikki qoida yordam beradi:
- Handler haqida bilish kerakmi? Kerak emas — middleware. Kerak (qaysi controller, qaysi dekorator) — guard yoki interceptor.
- Javobni ko'rish kerakmi? Kerak — interceptor. Faqat "o'tsinmi" — guard.
Masalan 415 tekshiruvi hozir jsonTanaKerak(req) — handler ichida, har metodda qo'lda. Guard bo'lsa, u handler'dan oldin ishlaydi va bitta joyda yoziladi. Kanon buni Zod va Standard Schema NestJS'da bosqichida qiladi.
6.1 Bitta so'rovni boshidan oxirigacha kuzatamiz
Jadvalni bitta haqiqiy holatda sinab ko'raylik. Mijoz POST /vazifalar yuboradi, tanasi JSON, lekin nom maydoni bo'sh. Hamma narsa yuqoridagi jadval bo'yicha joyiga ko'chgan, deb tasavvur qilamiz:
| Qadam | Mexanizm | Nima bo'ladi |
|---|---|---|
| 1 | middleware | sorovId beriladi, tana o'qiladi, log boshlanadi |
| 2 | guard | tana JSON — o'tkazadi |
| 3 | interceptor (oldin) | vaqt hisoblagichi ishga tushadi |
| 4 | pipe | Zod: nom bo'sh — xato tashlaydi |
| 5 | interceptor (xato) | xatoni ko'radi, lekin o'zgartirmaydi |
| 6 | filter | Problem Details, status 422 |
422 — 25-qismdagi qoida: tana mazmuni noto'g'ri. Handler bu so'rovni umuman ko'rmaydi — 4-qadamda zanjir uzildi. Ombor ham, baza ham chaqirilmadi. Middleware'dagi log esa so'rovni yozib qo'ydi, chunki u guard'dan ham, pipe'dan ham oldin turadi.
Endi tanasi text/plain bo'lgan so'rovni o'ylang. U 2-qadamda — guard'da — 415 bilan to'xtaydi. 3–5-qadamlar bo'lmaydi: interceptor ham, pipe ham ishga tushmaydi. Javobni filter beradi. Shunday qilib, bitta jadval ikki savolga javob beradi: xato qayerda chiqdi va undan keyingi qaysi qadamlar bajarilmadi.
Tekshirib ko'ring: Har javobga
X-Javob-Vaqti: 12mssarlavhasini qo'shish kerak. Middleware'mi, guard'mi yoki interceptor'mi?
Javob
Interceptor — handler'dan oldin vaqtni oladi, keyin javob tayyor bo'lganda farqni hisoblaydi. Middleware ham qila oladi (res.on("finish")), lekin u sarlavhani javob yuborilgandan keyin qo'sha olmaydi — finish paytida sarlavhalar ketib bo'lgan. Guard esa javobni umuman ko'rmaydi.
7. Nega loyihaga kirmadi
Bu darsda vazifalar-api ga kod qo'shilmaydi. Tajriba — tushunish uchun: har mexanizm o'z darsida loyihaga keladi va o'sha paytda shu tartib kerak bo'ladi. Masalan, keyinroq global auth guard (KirishGuard) qo'shilganda kanon bitta haqiqiy xato topadi: idempotentlik middleware bo'lgani uchun guard'dan oldin ishlab, anonim so'rovning 401 javobini keshlab qo'ygan. Tartibni bilmasangiz, bunday xatoni topish qiyin. Bu topilma auth darslarida (Global auth guard) batafsil.
8. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| Rad etilgan so'rovlar logda yo'q | log interceptor'da, guard undan oldin | so'rov logi — middleware |
| Global filtr javob bermadi | route yoki controller filtri bor — eng yaqini ishladi | filtrlarni bitta joyda saqlang |
Pipe req.user ni ko'rmaydi deb o'ylash |
aslida guard pipe'dan oldin — ko'radi | tartibni jadvaldan tekshiring |
useGlobalGuards(new X()) da DI ishlamaydi |
new bilan yaratilgan, konteynerdan tashqarida |
APP_GUARD provider |
| Middleware handler metama'lumotini o'qiy olmaydi | middleware Nest marshrutini bilmaydi | guard yoki interceptor |
9. Mashqlar
Mashqlar kurs/mashqlar/30/07-hayot-sikli/ da.
1-mashq (oson): tartibni toping
Bo'shliqlarni to'ldiring:
- Guard'dan oldin ishlaydigan mexanizm —
- Handler'dan keyin javobni ko'radigan mexanizm —
- Guard
falseqaytarsa, Nest qaysi statusni beradi? — - Xato bo'lganda nechta filter javob beradi? —
- Ikki global guard'dan qaysi biri oldin:
APP_GUARDyokiuseGlobalGuards? —
Yechim
- middleware — Express darajasida, Nest marshrutidan oldin.
- interceptor — "keyin" qismi; teskari tartibda.
- 403 —
ForbiddenException("Forbidden resource"). - 1 — eng yaqini (route → controller → global).
- APP_GUARD — kanon tajribasida 3-qator
APP_GUARD, 4-qatoruseGlobalGuards.
2-mashq (o'rta): interceptor xatoni yutadi
Darsdagi modelga qutqaruvchi sozlamasini qo'shing: true bo'lsa, eng ichki (route) interceptor xatoni ushlab, o'rniga {"zaxira":true} javob beradi — filter ishlamaydi, qolgan interceptor'lar esa muvaffaqiyat tarmog'idan (int<) o'tadi. Pipe xatosi bilan ikki holatni chiqaring: qutqaruvchi: false va true. Ishora: ichki catch da if (qutqaruvchi) tekshiruvi.
Yechim
const DARAJA = ["APP", "global", "controller", "route"];
function sorov(nom, { pipeXato, qutqaruvchi }) {
const iz = [];
try {
for (const d of DARAJA) iz.push(`int>${d}`);
try {
if (pipeXato) throw new Error("pipe rad etdi");
iz.push("HANDLER");
} catch (x) {
if (!qutqaruvchi) {
for (const d of DARAJA.toReversed()) iz.push(`int!${d}`);
throw x;
}
iz.push("int!route → zaxira");
}
const tashqi = DARAJA.toReversed().slice(qutqaruvchi ? 1 : 0);
for (const d of tashqi) iz.push(`int<${d}`);
iz.push(qutqaruvchi ? 'javob {"zaxira":true}' : "javob");
} catch (x) {
iz.push(`filter:route ← ${x.message}`);
}
console.log(`${nom}: ${iz.join(" ")}`);
}
sorov("yutmaydi", { pipeXato: true, qutqaruvchi: false });
sorov("yutadi", { pipeXato: true, qutqaruvchi: true });Konsolda:
yutmaydi: int>APP int>global int>controller int>route int!route int!controller int!global int!APP filter:route ← pipe rad etdi
yutadi: int>APP int>global int>controller int>route int!route → zaxira int<controller int<global int<APP javob {"zaxira":true}Ikkinchi qatorda filter yo'q: route interceptor xatoni javobga aylantirdi va tashqi interceptor'lar uni oddiy javob deb ko'rdi. Haqiqiy Nest'da bu RxJS catchError operatori bilan qilinadi (Interceptor'lar va RxJS). Kuchli imkoniyat, lekin xavfli: xato jim yo'qolishi mumkin — logga yozmasdan yutmang.
3-mashq (qiyin): eng yaqin filter @Catch turi bilan
Haqiqiy Nest'da filter faqat o'z turidagi xatoni ushlaydi: @Catch(HttpException) oddiy TypeError ni o'tkazib yuboradi va navbat keyingi darajaga o'tadi. filtrTanla(xato, filtrlar) funksiyasini yozing: filtrlar — [{ daraja: "route", tur: HttpXato }, …] (tartib: route → controller → global; tur: null — hamma xato). Birinchi mos keladigan filter nomini qaytarsin, hech biri bo'lmasa — "nest sukut (500)". Sinov: HttpXato va TypeError bilan, ikki xil filtrlar ro'yxatida. Ishora: find va instanceof.
Yechim
class HttpXato extends Error {}
function filtrTanla(xato, filtrlar) {
const f = filtrlar.find(
(k) => k.tur === null || xato instanceof k.tur,
);
return f ? f.daraja : "nest sukut (500)";
}
const royxat1 = [
{ daraja: "route", tur: HttpXato },
{ daraja: "global", tur: null },
];
const royxat2 = [{ daraja: "controller", tur: HttpXato }];
console.log(filtrTanla(new HttpXato("404"), royxat1));
console.log(filtrTanla(new TypeError("x"), royxat1));
console.log(filtrTanla(new TypeError("x"), royxat2));Konsolda:
route
global
nest sukut (500)TypeError route filtriga mos kelmadi — navbat globalga o'tdi. Uchinchi holatda mos filter yo'q: Nest'ning o'z sukut ishlovchisi {"statusCode":500,"message":"Internal server error"} beradi. vazifalar-api filtri @Catch() — argumentsiz, ya'ni tur: null: u hamma xatoni oladi va bunday "teshik" qolmaydi.
10. Real ishda
- Debug qilishda birinchi savol: "bu kod qaysi bosqichda?". Javob ko'pincha muammoni o'zi ochadi.
- Jamoa qoidasi: auth — guard, validatsiya — pipe, log va sarlavha — interceptor yoki middleware, xato formati — bitta global filter. Har bir qatlam bitta ish.
- Kod review: "bu tekshiruv nega handler ichida?" — guard yoki pipe'ga ko'chirish taklifi tez-tez uchraydi.
- Intervyu: "Nest request lifecycle tartibini ayting" — eng ko'p beriladigan Nest savollaridan biri. Qo'shimcha savol: "guard va middleware farqi nima?" (guard
ExecutionContextorqali handler'ni biladi).
Xulosa
- Tartib: middleware → guard → interceptor (oldin) → pipe → handler → interceptor (keyin, teskari) → javob.
- Har bosqichda: global (
APP_*, keyinuseGlobal*) → controller → route; pipe'da yana parametr darajasi. - Guard rad etsa — 403, interceptor/pipe/handler ishlamaydi; filter — eng yaqini.
- Pipe va handler xatosini interceptor xato tarmog'ida ko'radi; javobni faqat bitta filter beradi.
- Har vazifaga mexanizm: "handler'ni bilish kerakmi?" va "javobni ko'rish kerakmi?" degan savollar bilan tanlanadi.
Keyingi dars: DI va IoC konteyner — Nest konteyneri bog'liqliklarni qanday "ko'rishini" design:paramtypes orqali, tipik xatolarini esa haqiqiy matnlari bilan ko'ramiz.
Manbalar
- NestJS hujjati — Request lifecycle: https://docs.nestjs.com/faq/request-lifecycle
- NestJS hujjati — Guards, Interceptors, Pipes, Exception filters: https://docs.nestjs.com/guards , https://docs.nestjs.com/interceptors , https://docs.nestjs.com/pipes , https://docs.nestjs.com/exception-filters
- Kanon tajribasi (IlmHamroh, 2026-10-27): to'rt darajadagi hamma mexanizm, to'rt so'rov (muvaffaqiyat, pipe xatosi, handler xatosi, guard rad etishi), NestJS 12.2.0, Node 24.21.0, Vitest muhitida.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!