Skip to content

Middleware

Middleware 是一种在路由 handler 之前被调用的函数。Middleware 可以访问 Request 和 Response,其中的 next() 方法用于调用下一个 Middleware。

创建 Middleware

新建 Middleware。

sh
nest g middleware aaa

将 Express 的类型补充完整,并在路由前后添加逻辑。

ts
import { Injectable, NestMiddleware } from '@nestjs/common'
import { Request, Response } from 'express'

@Injectable()
export class AaaMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: () => void) {
    console.log('before')

    next()

    console.log('after')
  }
}

在 Module 里声明。

ts
@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(AaaMiddleware).forRoutes('*')
  }
}

可以看到,Middleware 的逻辑都执行了。

针对路由的 Middleware

Middleware 可以针对指定路由执行。

在 Controller 中添加几个 handler。

ts
@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get('/hello1')
  getHello1(): string {
    return 'Hello1'
  }

  @Get('/hello2')
  getHello2(): string {
    return 'Hello2'
  }

  @Get('/hello3')
  getHello3(): string {
    return 'Hello3'
  }

  @Get('/world')
  getWorld(): string {
    return 'world'
  }
}

重新指定 Middleware 的路由。

ts
@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(AaaMiddleware)
      .forRoutes({ path: 'hello*', method: RequestMethod.GET })
  }
}

可以看到,hello 的路由都调用了 Middleware,而 world 的路由没有。

依赖注入

Nest 的 Middleware 也可以进行依赖注入。

下面的代码将 AppService 注入到目前的 Middleware 中。

ts
@Injectable()
export class AaaMiddleware implements NestMiddleware {
  @Inject(AppService)
  private readonly appService: AppService

  use(req: Request, res: Response, next: () => void) {
    console.log('before')

    console.log(`${this.appService.getHello()}`)

    next()

    console.log('after')
  }
}

改成构造器注入,效果相同。

ts
@Injectable()
export class AaaMiddleware implements NestMiddleware {
  constructor(private readonly appService: AppService) {}

  use(req: Request, res: Response, next: () => void) {
    console.log('before')

    console.log(`${this.appService.getHello()}`)

    next()

    console.log('after')
  }
}

@Next 装饰器

Next 装饰器用于调用下一个 handler。在这段代码中,访问 /hello1 最终会返回 Hello5

ts
@Get('/hello1')
getHello1(@Next() next): string {
  next();
  return 'Hello1';
}

@Get('/hello1')
getHello5(): string {
  return 'Hello5';
}

一般来说,这些逻辑写在一个 handler 中即可。

Middleware 和 Interceptor 的区别

Nest 的 Middleware 和 Interceptor 都能在请求前后加入一些逻辑,那么这两者的区别是什么呢?

Interceptor 能从 ExecutionContext 中取到目标 class 和 handler,进一步通过 Reflector 拿到 Metadata 等;或者是可以用 rxjs 的操作符来组织响应处理流程。而 Middleware 则都不能做到。

那么,Interceptor 适合处理业务逻辑,而 Middleware 则适合处理通用逻辑。

Released under the MIT License.