nest系列 - 中间件

72 阅读2分钟

中间件

中间件是在路由处理程序之前调用的函数。中间件函数 可以访问请求和响应对象,以及应用程序请求。下一个中间件函数通常由名为 next 的变量表示。

Middlewares_1.png

中间件函数可以执行以下任务:

  • 对请求和响应对象进行更改。
  • 调用堆栈中的下一个中间件函数。
  • 如果当前中间件函数没有结束请求-响应周期,则必须调用 next() 将控制权传递给下一个中间件函数。否则,请求将保持挂起状态。

可以在 函数 中实现自定义 Nest 中间件,也可以在具有 @Injectable() 装饰器的类中实现。该类应实现 NestMiddleware 接口,而该函数没有任何特殊要求。

logger.middleware.ts

使用 calss 方法定义一个中间件

import { Injectable, NestMiddleware, Body } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log('Request...');
    next();
  }
}

也可以使用 函数 定义中间件

export function logger(req: Request, res: Response, next: NextFunction) {
  console.log(`LOGGER...`);
  next();
};

使用中间件

基础使用

实现 NestModule 接口,在 forRoutes 传入要使用中间件的 controller 的路径

app.module.ts

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [CatsModule],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes('cats');
  }
}

cat.controller

@Controller("cats")
export class CatsController{}

指定请求方法

forRoutes 可以传入一个对象, path 表示的是要使用的 controller 名称,method 表示允许使用中间件的 方法

在下面的例子中,我们配置 methodget,那么在 cats 中的 post 方法无法使用 中间件

import { Module, NestModule, RequestMethod, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [CatsModule],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes({ path: 'cats', method: RequestMethod.GET });
  }
}

路由通配符

可以使用正则表达式,例如,星号 用作通配符,并将匹配任意字符组合:

import { Module, NestModule, RequestMethod, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [CatsModule],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(LoggerMiddleware).forRoutes({ 
        path: 'cat*', method: RequestMethod.ALL
      });
  }
}

传入控制器

可以直接传入控制器

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';
import { CatsController } from './cats/cats.controller';

@Module({
  imports: [CatsModule],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes(CatsController);
  }
}

排除路由

我们可以使用 exclude() 方法轻松排除某些路由,下图的方式是排除 cats 路由中的 Get方法

consumer
  .apply(LoggerMiddleware)
  .exclude(
    { path: 'cats', method: RequestMethod.GET },
  )
  .forRoutes(CatsController);

多个中间件

多个中间件使用逗号连接

    consumer
     .apply(LoggerMiddleware,logger)
     .forRoutes(CatsController,ListController);  

全局中间件

import { logger } from './middlewares/logger.middleware';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  generateDocument(app);
  // *** 中间件
  app.use(logger)
  // ***
  app.useGlobalPipes(new ValidationPipe());
  await app.listen(3001);
}
bootstrap();

链接: nest官方文档 - middleware