中间件的介绍
- 中间件是在理由处理程序
之前
调用的函数。 - 中间件函数可以访问
请求对象
和响应对象
,以及请求响应周期中的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);
网友评论