中间件、守卫、管道、拦截器、异常过滤器、验证器
前言
Nest.js 作为一个强大的 Node.js 框架,提供了一套丰富的装饰器和帮助函数来支持 AOP 的实现。其中 Nest 的实现主要包括如下五种:
- 中间件(Middleware)
- 守卫(Guard)
- 管道(Pipe)
- 拦截器(Interceptor)
- 安装
npm install --save rxjs xml2js class-validator class-transformer
中间件
Middleware是在路由处理程序之前调用的函数。中间件函数可以访问请求和响应对象,以及应用程序的请求-响应周期中的next()
中间件函数。通常,next中间件函数由一个名为next
的变量表示
中间件函数可以执行以下任务:
-
执行任何代码
-
对请求和响应对象进行更改
-
结束请求-响应周期
-
调用堆栈中的下一个中间件函数
-
如果当前中间件函数未结束请求-响应周期,则必须调用
next()
将控制权传递给下一个中间件函数。否则,请求将被搁置 -
创建logger.middleware.ts中间件
nest g mi logger --no-spec --flat
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
console.log('Logger 中间件拦截', req.header);
// 具体内容根据需求去写
next();
}
}
1、局部中间件
- demo.module.ts
import { Module, NestMiddleware, MiddlewareConsumer } from '@nestjs/common';
import { DemoService } from './demo.service';
import { DemoController } from './demo.controller';
import {LoggerMiddleware} from '@/common/middleware/logger.middleware'
@Module({
controllers: [DemoController],
providers: [DemoService],
exports: [DemoService],
})
export class DemoModule implements NestMiddleware {
configure (consumer:MiddlewareConsumer) {
// consumer.apply(LoggerMiddleware).forRoutes('demo')
consumer.apply(LoggerMiddleware).forRoutes({path:'/demo',method:RequestMethod.GET}) //针对 Get
}
}
执行接口就能监听到结果l
2、全局中间件
- main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from '@/app.module';
function LoggerMiddleware(req, res, next: () => any) {
console.log(req.originalUrl, '我是全局中间件LoggerMiddleware')
next()
}
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(middleWareAll)
await app.listen(3000);
}
bootstrap();
请求demo与user接口都监听到结果了
守卫
守卫具有单一职责。它们根据运行时的某些条件(如权限、角色、ACL等)确定是否将处理给定请求,这通常称为授权。授权(以及它通常与之协作的身份验证)通常在传统的Express应用程序中由中间件处理。中间件是身份验证的不错选择,因为诸如令牌验证和将属性附加到request
对象之类的事情与特定路由上下文(及其元数据)没有紧密关联
- 创建auth.guard.ts 守卫
nest g gu auth --no-spec --flat
import { Reflector } from '@nestjs/core'
import { AuthGuard } from '@nestjs/passport'
import { ExecutionContext, ForbiddenException, Inject, Injectable, UnauthorizedException } from '@nestjs/common'
import { UserService } from '@/modules/user/user.service';
import { ALLOW_ANON } from '@/common/decorator/allow-anon.decorator'
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
constructor(private readonly reflector: Reflector, @Inject(UserService)
private readonly userService: UserService) {
super()
}
async canActivate(ctx: ExecutionContext): Promise<boolean> {
const allowAnon = this.reflector.getAllAndOverride<boolean>(ALLOW_ANON, [ctx.getHandler(), ctx.getClass()])
if (allowAnon) return true
const req = ctx.switchToHttp().getRequest()
const accessToken = req.get('Authorization')
if (!accessToken) throw new ForbiddenException('请先登录!')
const UserId = this.userService.verifyToken(accessToken)
if (!UserId) throw new UnauthorizedException('当前登录已过期,请重新登录!')
return this.activate(ctx)
}
async activate(ctx: ExecutionContext): Promise<boolean> {
return super.canActivate(ctx) as Promise<boolean>
}
}
- 全局注册守卫
import { Module, ValidationPipe } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './modules/user/user.module';
import { DemoModule } from './modules/demo/demo.module';
import { JwtAuthGuard } from '@/common/guard/auth.guard'
@Module({
imports: [ConfigModule.forRoot(), UserModule, DemoModule,],
controllers: [AppController],
providers: [AppService, {
// 全局权限认证
provide: APP_GUARD,
useClass: JwtAuthGuard,
}],
})
export class AppModule { }
管道
管道是具有 @Injectable()
装饰器的类。管道应实现 PipeTransform
接口。
管道有两个典型的应用场景:
- 转换:管道将输入数据转换为所需的数据输出(例如,将字符串转换为整数)
- 验证:对输入数据进行验证,如果验证成功继续传递; 验证失败则抛出异常
Nest
自带九个开箱即用的管道,即
ValidationPipe
ParseIntPipe
ParseFloatPipe
ParseBoolPipe
ParseArrayPipe
ParseUUIDPipe
ParseEnumPipe
DefaultValuePipe
ParseFilePipe
他们从 @nestjs/common
包中导出。
- 创建demo.pipe.ts管道
nest g pipe demo --no-spec --flat
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';
@Injectable()
export class DemoPipe implements PipeTransform {
transform(value: any, metadata: ArgumentMetadata) {
//这个里面可以修改传入的值以及验证转入值的合法性
console.log("我是处理Demo参数管道");
return value;
}
}
- 全局管道注册
import { DemoPipe } from '@/common/pipe/demo.pipe';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new DemoPipe()); a
wait app.listen(3000);
}
bootstrap();
- 或者
import { Module } from '@nestjs/common';
import { APP_PIPE } from '@nestjs/core';
import { DemoPipe } from '@/common/pipe/demo.pipe';
@Module({
providers: [ { provide: APP_PIPE, useClass: DemoPipe } ]
})
export class AppModule {}
- Demo控制中使用
@Post()
@SwaggerDoc("创建demo", "demo描述", "创建demo请求", String)
create(@Body(new DemoPipe()) createDemoDto: CreateDemoDto) {
return this.demoService.create(createDemoDto);
}
拦截器
拦截器具有一系列有用的功能,这些功能受面向切面编程(AOP)技术的启发。它们可以
- 在函数执行之前/之后绑定额外的逻辑
- 转换从函数返回的结果
- 转换从函数抛出的异常
- 扩展基本函数行为
- 根据所选条件完全重写函数 (例如, 缓存目的)
- 创建transform.interceptor.ts 拦截器
nest g itc interceptor/transform --no-spec --flat
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from "@nestjs/common"
import { Observable } from "rxjs"
import { map } from 'rxjs/operators';
interface Response<T> {
data: T;
}
@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
intercept(context: ExecutionContext, next: CallHandler<T>): Observable<Response<T>> | Promise<Observable<Response<T>>> {
return next.handle().pipe(
map((data) => ({
code: 0, //状态码
data,//返回数据
pagination: { //分页
total: 100,
pageSize: 10,
pages: 10,
page: 1,
},
extra: {}, // 拓展
message: 'success',// 返回结果
})),
);
}
}
- 在app.module.ts全局注册
import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './modules/user/user.module';
import { DemoModule } from './modules/demo/demo.module';
import { TransformInterceptor } from '@/common/interceptor/transform.interceptor';
@Module({
imports: [ConfigModule.forRoot(), UserModule, DemoModule,],
controllers: [AppController],
providers: [AppService, {
// 全局拦截器
provide: APP_INTERCEPTOR,
useClass: TransformInterceptor,
}],
})
export class AppModule { }
- 或者main.ts注册
import { TransformInterceptor } from '@/common/interceptor/transform.interceptor';
app.useGlobalInterceptors(new TransformInterceptor())
异常过滤器
Nest框架内置了一个异常处理层,负责处理应用程序中的所有未处理异常。当一个异常没有被应用程序代码处理时,它会被这个异常处理层捕获,然后自动发送一个适当的用户友好响应。
- 创建http.exception.filter.ts异常过滤器
nest g f http.exception --no-spec --flat
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { Request, Response } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const request = host.switchToHttp().getRequest<Request>();
const response = host.switchToHttp().getResponse<Response>();
// http异常处理
response.status(HttpStatus.NOT_FOUND).send({
statusCode: HttpStatus.NOT_FOUND,
timestamp: new Date().toISOString(),
path: request.url,
message: exception.getResponse(),
});
}
}
- main.ts注册
import { HttpExceptionFilter } from '@/common/filters/exceptions/http.exception.filter';
app.useGlobalFilters(new HttpExceptionFilter())
- 或app.module.ts注册
import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './modules/user/user.module';
import { DemoModule } from './modules/demo/demo.module';
import { HttpExceptionFilter } from '@/common/filters/exceptions/http.exception.filter';
@Module({
imports: [ConfigModule.forRoot(), UserModule, DemoModule,],
controllers: [AppController],
providers: [AppService, {
// Http异常
provide: APP_FILTER,
useClass: HttpExceptionFilter,
},],
})
export class AppModule { }
验证器
import { IsNotEmpty, IsString, Length, IsIn,IsNumber } from 'class-validator'
export class CreateDemoDto {
@IsNotEmpty()//验证是否为空
@IsString() //是否为字符串
@Length(1, 10)
username: string;
@IsNotEmpty()
@IsNumber()
age: number
@IsIn([0, 1])
status: number;
}
- 全局注册Nest内置ValidationPipe验证管道
github
项目地址:nest-vhen-blog