中间件
Nest 中间件实际上等价于 express 中间件。 下面是Express官方文档中所述的中间件功能:
中间件函数可以执行以下任务:
- 执行任何代码。
- 对请求和响应对象进行更改。
- 结束请求-响应周期。
- 调用堆栈中的下一个中间件函数。
- 如果当前的中间件函数没有结束请求-响应周期, 它必须调用
next()
将控制传递给下一个中间件函数。否则, 请求将被挂起。
您可以在函数中或在具有 @Injectable()
装饰器的类中实现自定义 Nest
中间件。 这个类应该实现 NestMiddleware
接口, 而函数没有任何特殊的要求。 让我们首先使用类方法实现一个简单的中间件功能。
Nest
中间件完全支持依赖注入。 就像提供者和控制器一样,它们能够注入属于同一模块的依赖项(通过 constructor
)。
应用中间件
中间件不能在 @Module()
装饰器中列出。我们必须使用模块类的 configure()
方法来设置它们。包含中间件的模块必须实现 NestModule
接口。我们将 LoggerMiddleware
设置在 ApplicationModule
层上。
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 {
consumer
.apply(LoggerMiddleware)
.forRoutes('cats');
}
import { Module, NestModule, RequestMethod, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
@Module({
imports: [CatsModule],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes({ path: 'cats', method: RequestMethod.GET });
}
}
?> 可以使用 async/await
来实现 configure()
方法的异步化(例如,可以在 configure()
方法体中等待异步操作的完成)。
路由同样支持模式匹配。例如,星号被用作通配符,将匹配任何字符组合。
以上路由地址将匹配 abcd
、 ab_cd
、 abecd
等。字符 ?
、 +
、 *
以及 ()
是它们的正则表达式对应项的子集。连字符 (-
) 和点 (.
) 按字符串路径解析。
?> 该 fastify
软件包使用该软件包的最新版本,该版本 path-to-regexp
不再支持通配符星号。相反,您必须使用参数(例如(`.),
:splat*`)。
中间件消费者
MiddlewareConsumer
是一个帮助类。它提供了几种内置方法来管理中间件。他们都可以被简单地链接起来。forRoutes()
可接受一个字符串、多个字符串、对象、一个控制器类甚至多个控制器类。在大多数情况下,您可能只会传递一个由逗号分隔的控制器列表。以下是单个控制器的示例:
app.module.ts
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';
@Module({
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes(CatsController);
}
}
?> 该 apply()
方法可以使用单个中间件,也可以使用多个参数来指定多个多个中间件。
consumer
.apply(LoggerMiddleware)
.exclude(
{ path: 'cats', method: RequestMethod.GET },
{ path: 'cats', method: RequestMethod.POST },
'cats/(.*)',
)
.forRoutes(CatsController);
?> 该 exclude()
方法使用 path-to-regexp
包支持通配符参数。
在上面的示例中,LoggerMiddleware
将绑定到内部定义的所有路由,CatsController
但传递给 exclude()
方法的三个路由除外。
我们使用的 LoggerMiddleware
类非常简单。它没有成员,没有额外的方法,没有依赖关系。为什么我们不能只使用一个简单的函数?这是一个很好的问题,因为事实上 - 我们可以做到。这种类型的中间件称为函数式中间件。让我们把 logger
转换成函数。
现在在 AppModule
中使用它。
app.module.ts
consumer
.apply(logger)
?> 当您的中间件没有任何依赖关系时,我们可以考虑使用函数式中间件。
多个中间件
如前所述,为了绑定顺序执行的多个中间件,我们可以在 apply()
方法内用逗号分隔它们。
consumer.apply(cors(), helmet(), logger).forRoutes(CatsController);
@Armor | | 翻译 | 专注于 Java 和 Nest,
| @tangkai | | 翻译 | 专注于 React, |
| @havef |
| 校正 | 数据分析、机器学习、TS/JS技术栈 |
| @gaoyangy | | 校正 | 专注于Vue,TS/JS |