Middleware
Middleware - route handlerdan oldin chaqiriladigan funksiya. Middleware funksiyalari ilovaning request-response siklidagi request va response obyektlariga hamda next() middleware f
Middleware - route handlerdan oldin chaqiriladigan funksiya. Middleware funksiyalari ilovaning request-response siklidagi request va response obyektlariga hamda next() middleware funksiyasiga kirish huquqiga ega. Next middleware funksiyasi odatda next deb nomlangan o'zgaruvchi bilan belgilanadi.
Nest middlewarelari odatda express middlewarelariga teng. Rasmiy express hujjatlaridagi quyidagi ta'rif middleware imkoniyatlarini bayon qiladi:
Middleware funksiyalari quyidagi vazifalarni bajarishi mumkin:
- istalgan kodni bajarish.
- request va response obyektlariga o'zgartirish kiritish.
- request-response siklini yakunlash.
- stekdagi keyingi middleware funksiyasini chaqirish.
- agar joriy middleware funksiyasi request-response siklini yakunlamasa, boshqaruvni keyingi middleware funksiyasiga o'tkazish uchun
next()ni chaqirishi shart. Aks holda, so'rov javobsiz qoladi.
Maxsus Nest middleware ni funksiya ko'rinishida yoki @Injectable() dekoratori bilan sinf ko'rinishida amalga oshirasiz. Sinf NestMiddleware interfeysini amalga oshirishi kerak, funksiya esa maxsus talablarga ega emas. Keling, sinf usuli orqali oddiy middleware funksiyasini amalga oshirishdan boshlaylik.
Express va fastify middleware ni turlicha qayta ishlaydi va turli metod imzolarini taqdim etadi, batafsil bu yerda o'qing.
1import { Injectable, NestMiddleware } from '@nestjs/common';
2import { Request, Response, NextFunction } from 'express';
3
4@Injectable()
5export class LoggerMiddleware implements NestMiddleware {
6 use(req: Request, res: Response, next: NextFunction) {
7 console.log('Request...');
8 next();
9 }
10}Bog'liqliklarni in'eksiya qilish
Nest middleware Dependency Injectionni to'liq qo'llab-quvvatlaydi. Provayderlar va kontrollerlar singari, ular xuddi shu modul doirasida mavjud bo'lgan bog'liqliklarni in'eksiya qila oladi. Odatdagidek, bu constructor orqali amalga oshiriladi.
Middleware ni qo'llash
@Module() dekoratorida middleware uchun joy yo'q. Buning o'rniga ularni modul sinfining configure() metodi orqali sozlaymiz. Middlewarega ega bo'lgan modullar NestModule interfeysini amalga oshirishi kerak. LoggerMiddleware ni AppModule darajasida sozlaylik.
1import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
2import { LoggerMiddleware } from './common/middleware/logger.middleware';
3import { CatsModule } from './cats/cats.module';
4
5@Module({
6 imports: [CatsModule],
7})
8export class AppModule implements NestModule {
9 configure(consumer: MiddlewareConsumer) {
10 consumer
11 .apply(LoggerMiddleware)
12 .forRoutes('cats');
13 }
14}Yuqoridagi misolda biz CatsController ichida avval aniqlangan /cats route handlerlari uchun LoggerMiddleware ni sozladik. Middleware ni muayyan so'rov metodiga cheklash uchun, middleware ni sozlashda forRoutes() metodiga route path va so'rov method ini o'z ichiga olgan obyektni uzatish mumkin. Quyidagi misolda kerakli so'rov metodi turini ko'rsatish uchun RequestMethod enumini import qilayotganimizga e'tibor bering.
1import { Module, NestModule, RequestMethod, MiddlewareConsumer } from '@nestjs/common';
2import { LoggerMiddleware } from './common/middleware/logger.middleware';
3import { CatsModule } from './cats/cats.module';
4
5@Module({
6 imports: [CatsModule],
7})
8export class AppModule implements NestModule {
9 configure(consumer: MiddlewareConsumer) {
10 consumer
11 .apply(LoggerMiddleware)
12 .forRoutes({ path: 'cats', method: RequestMethod.GET });
13 }
14}configure() metodini async/await yordamida asinxron qilish mumkin (masalan, configure() metod tanasi ichida asinxron operatsiya yakunlanishini await qilishingiz mumkin).
express adapteridan foydalanganda, NestJS ilovasi odatda body-parser paketidan json va urlencoded ni ro'yxatdan o'tkazadi. Bu shuni anglatadiki, MiddlewareConsumer orqali ushbu middleware ni sozlamoqchi bo'lsangiz, NestFactory.create() bilan ilova yaratishda bodyParser bayrog'ini false qilib, global middleware ni o'chirishingiz kerak bo'ladi.
Marshrut wildcardlari
Shablon asosidagi marshrutlar NestJS middlewarelarida ham qo'llab-quvvatlanadi. Masalan, nomlangan wildcard (*splat) marshrutdagi har qanday belgilar kombinatsiyasiga mos keluvchi wildcard sifatida ishlatilishi mumkin. Quyidagi misolda middleware abcd/ bilan boshlanuvchi har qanday marshrut uchun, undan keyin qancha belgi kelishidan qat'i nazar, bajariladi.
1forRoutes({
2 path: 'abcd/*splat',
3 method: RequestMethod.ALL,
4});splat shunchaki wildcard parametrining nomi bo'lib, maxsus ma'noga ega emas. Uni xohlagan nom bilan atashingiz mumkin, masalan, *wildcard.
'abcd/*' route pathi abcd/1, abcd/123, abcd/abc va hokazolarga mos keladi. Tire (-) va nuqta (.) satrga asoslangan pathlar tomonidan literal tarzda talqin qilinadi. Biroq, qo'shimcha belgilar bo'lmagan abcd/ marshruti mos kelmaydi. Buning uchun wildcard ni qavslar ichiga olib, uni ixtiyoriy qilish kerak:
1forRoutes({
2 path: 'abcd/{*splat}',
3 method: RequestMethod.ALL,
4});Middleware consumer
MiddlewareConsumer yordamchi sinfdir. U middlewarelarni boshqarish uchun bir nechta o'rnatilgan metodlarni taqdim etadi. Ularning barchasini fluent uslubda oddiygina zanjirlash mumkin. forRoutes() metodi bitta satr, bir nechta satrlar, RouteInfo obyekti, kontroller sinfi va hatto bir nechta kontroller sinflarini qabul qilishi mumkin. Ko'p hollarda siz vergul bilan ajratilgan kontrollerlar ro'yxatini uzatasiz. Quyida bitta kontroller bilan misol keltirilgan:
1import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
2import { LoggerMiddleware } from './common/middleware/logger.middleware';
3import { CatsModule } from './cats/cats.module';
4import { CatsController } from './cats/cats.controller';
5
6@Module({
7 imports: [CatsModule],
8})
9export class AppModule implements NestModule {
10 configure(consumer: MiddlewareConsumer) {
11 consumer
12 .apply(LoggerMiddleware)
13 .forRoutes(CatsController);
14 }
15}apply() metodi bitta middleware ni yoki bir nechta middleware ni ko'rsatish uchun bir nechta argumentni qabul qilishi mumkin. bir nechta middleware.
Marshrutlarni istisno qilish
Ba'zan ayrim marshrutlarga middleware qo'llanmasligini istisno qilishni xohlaymiz. Buni exclude() metodidan foydalanib oson amalga oshirish mumkin. exclude() metodi istisno qilinadigan marshrutlarni aniqlash uchun bitta satr, bir nechta satr yoki RouteInfo obyektini qabul qiladi.
Quyida qanday ishlatish misoli:
1consumer
2 .apply(LoggerMiddleware)
3 .exclude(
4 { path: 'cats', method: RequestMethod.GET },
5 { path: 'cats', method: RequestMethod.POST },
6 'cats/{*splat}',
7 )
8 .forRoutes(CatsController);exclude() metodi wildcard parametrlarini path-to-regexp paketi yordamida qo'llab-quvvatlaydi.
Yuqoridagi misolda LoggerMiddleware CatsController ichida aniqlangan barcha marshrutlarga ulanadi, exclude() metodiga uzatilgan uchtasidan tashqari.
Bu yondashuv middlewarelarni muayyan marshrutlar yoki marshrut shablonlariga qarab qo'llash yoki chiqarib tashlashda moslashuvchanlik beradi.
Funksional middleware
Biz ishlatib kelayotgan LoggerMiddleware sinfi juda sodda. Uning a'zolari yo'q, qo'shimcha metodlari yo'q, bog'liqliklari ham yo'q. Nega uni sinf o'rniga oddiy funksiya sifatida aniqlamasligimiz kerak? Aslida, buni qila olamiz. Bunday turdagi middleware funksional middleware deb ataladi. Farqini ko'rsatish uchun logger middleware ni sinf asosidan funksional middleware ga o'zgartiraylik:
1import { Request, Response, NextFunction } from 'express';
2
3export function logger(req: Request, res: Response, next: NextFunction) {
4 console.log(`Request...`);
5 next();
6};Va uni AppModule ichida ishlatamiz:
1consumer
2 .apply(logger)
3 .forRoutes(CatsController);Middlewarega hech qanday bog'liqlik kerak bo'lmaganida, soddaroq funksional middleware variantidan foydalanishni ko'rib chiqing.
Bir nechta middleware
Yuqorida aytilganidek, ketma-ket bajariladigan bir nechta middleware ni ulash uchun apply() metodi ichida vergul bilan ajratilgan ro'yxatni berish kifoya:
1consumer.apply(cors(), helmet(), logger).forRoutes(CatsController);Global middleware
Agar middleware ni ro'yxatdan o'tgan barcha marshrutlarga bir vaqtning o'zida ulamoqchi bo'lsak, INestApplication instansiyasi taqdim etadigan use() metodidan foydalanishimiz mumkin:
1const app = await NestFactory.create(AppModule);
2app.use(logger);
3await app.listen(process.env.PORT ?? 3000);Global middleware ichida DI konteyneriga kirish mumkin emas. app.use() ishlatilganda uning o'rniga funksional middlewaredan foydalanishingiz mumkin. Muqobil ravishda, sinf middleware dan foydalanib, AppModule (yoki boshqa modul) ichida .forRoutes('*') bilan iste'mol qilishingiz mumkin.