Nest.js - Middleware

中间件的介绍
  • 中间件是在理由处理程序之前调用的函数。
  • 中间件函数可以访问请求对象响应对象,以及请求响应周期中的next()中间件函数
  • Nest中间件实际上就是底层Express中间件

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

  • 执行任何代码
  • 请求和响应对象进行更改
  • 结束请求-响应周期
  • 调用堆栈中的下一个中间件函数
  • 如没有结束请求-响应周期,那么必须调用next()将控制交给下一个中间件函数,否则请求将被挂起
自定义中间件的实现
  • 普通函数中实现Nest中间件
  • 具有 @Injectable() 装饰器的类中,实现NestMiddleware接口来实现Nest中间件
//logger.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: Function) {
    console.log('Request...');
    next();
  }
}
中间件的应用
  • 使用中间件的模块必须实现NestModule接口
  • 必须使用模块类configure()方法来设置中间件
  • (此处将 LoggerMiddleware 设置在 ApplicationModule 层上)
import { Module, NestModule, MiddlewareConsumer } form '@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'); //  在限定的'/cats'路由路径下的处理程序中设置了LoggerMiddleware
  }
}
  • 配置中间件时将包含路由路径的对象和请求方法传递给forRoutes()方法,来限定在特定路由和请求方法下再调用中间件
  • 可以使用 async/await来实现configure()方法的异步化(例如,可以在 configure()方法体中等待异步操作的完成)
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 });
  }
}
  • 路由同样支持模式匹配:字符?+*以及()是它们的正则表达式对应项的子集。连字符 (-) 和点 (.) 按字符串路径解析
forRoutes({ path: 'ab*cd', method: RequestMethod.ALL });
中间件消费者
  • MiddlewareConsumer 是一个帮助类,提供了几种内置方法管理中间件,各方法之间可以级联
  • forRoutes()可以接受一个/多个字符串对象,一个/多个控制器类。(大多数情况下,传递一个由逗号分隔的控制器列表)
  • apply()可使用单个/多个中间件
  • 采用exclude()可在使用某些中间件时排除某些路由,参数是一个/多个字符串,或者RouteInfo对象
//app.module.ts - 单个控制器类(CatsController)
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.ts';

@Module({
  imports: [CatsModule],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes(CatsController);
  }
}
// 对CatsController中所有注册的路由(除了exclude()标注的之外)使用中间件LoggerMiddleware
consumer
  .apply(LoggerMiddleware)
  .exclude(
    { path: 'cats', method: RequestMethod.GET },
    { path: 'cats', method: RequestMethod.POST },
    'cats/(.*)',
  )
  .forRoutes(CatsController);
函数式中间件
  • 当一个中间件,除了req,res, next之外,没有成员,没有额外的方法,没有依赖关系,那么最好简化成函数式中间件
//中间件的定义: logger.middleware.ts
export function logger(req, res, next) {
  console.log(`Request...`);
  next();
};
//中间件的使用: app.module.ts
consumer
  .apply(logger)
  .forRoutes(CatsController);
多个中间件
consumer.apply(cors(), helmet(), logger).forRoutes(CatsController);
全局中间件
  • 使用由INestApplication实例提供的 use()方法
    +而NestFactory.create()返回的就是一个实现 INestApplication 接口的对象:app
const app = await NestFactory.create(AppModule);
app.use(logger);
await app.listen(3000);

你可能感兴趣的:(Nest.js - Middleware)