Nest中各类组件使用及请求链路

1、Nest中有什么组件

  • 中间件(Middleware)
  • 异常过滤器(Exception filters)
  • 拦截器(Interceptors)
  • 守卫(Guards)
  • 管道(Pipes)

2、各组件主要用法

1、中间件

仅在调用路由处理程序之前调用中间件。可以访问响应对象,但是没有路由处理程序的结果。
Nest中各类组件使用及请求链路

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

  • 执行任何代码。
  • 对请求和响应对象进行更改。(使用send函数直接返回客户端,直接中断后面的流程)
  • 结束请求-响应周期。
  • 调用堆栈中的下一个中间件函数。
  • 如果当前的中间件函数没有结束请求-响应周期, 它必须调用 next() 将控制传递给下一个中间件函数。否则, 请求将被挂起。

适用场景:

1、比如可以使用一个中间件记录到达的请求,为请求设置HTTP头部信息,再将请求传递给下一步。

2、日志记录

3、请求监控

1、全局中间件

1、定义全局中间件:

export async function markMiddleware(req: any, res: any, next: () => void){
        console.log('全局中间件 Global MarkMiddleware ');
        next();
}

Nest中各类组件使用及请求链路
2、注册全局中间件

import {NestFactory} from '@nestjs/core';
import {AppModule} from './app.module';
import {markMiddleware} from "./middleware/mark.middleware";
import {GlobalHttpExceptionFilter} from "./filter/GlobalHttpExceptionFilter";
import {GlobalAllExceptionFilter} from "./filter/GlobalAllExceptionFilter";
import {GlobalLoggingInterceptor} from "./interceptor/GlobalLogging.interceptor";
import {AuthGuard} from "./guard/AuthGuard";
import {GlobalValidationPipe} from "./pipe/GlobalValidate.pipe";

async function bootstrap() {
    const app = await NestFactory.create(AppModule);
    app.useGlobalPipes(new GlobalValidationPipe())
    app.useGlobalGuards(new AuthGuard())
    app.useGlobalInterceptors(new GlobalLoggingInterceptor())
    app.useGlobalFilters(new GlobalHttpExceptionFilter())
    app.useGlobalFilters(new GlobalAllExceptionFilter())

    app.use(markMiddleware)
    await app.listen(3001);
}

bootstrap();

Nest中各类组件使用及请求链路

2、局部中间件

1、定义控制层中间件

import {Injectable, NestMiddleware} from "@nestjs/common";

@Injectable()
export class LoggerMiddleware implements NestMiddleware{
    use(req: any, res: any, next: () => void): any {
        console.log('控制层中间件 LoggerMiddleware');
        next();
    }
}

Nest中各类组件使用及请求链路
2、注册中间件

import {MiddlewareConsumer, Module, NestModule} from '@nestjs/common';
import {AppController} from './app.controller';
import {AppService} from './app.service';
import {SharedModule} from './shared/shared.module';
import {FeatureModule} from "./feature/feature.module";
import {LoggerMiddleware} from "./middleware/logger.middleware";

@Module({
    imports: [SharedModule, FeatureModule],
    controllers: [AppController],
    providers: [AppService],
    exports:[]
})
export class AppModule implements NestModule{
    configure(consumer: MiddlewareConsumer): any {
        consumer.apply(LoggerMiddleware)
            .forRoutes(AppController)
    }
}

Nest中各类组件使用及请求链路

3、中间件执行顺序

全局绑定的中间件(有多个就按注册顺序执行) -> 模块绑定的中间件(有多个就按注册顺序执行)
Nest中各类组件使用及请求链路

2、异常过滤器

异常过滤器在路由处理程序之后和拦截器之后调用。它们是在响应到达客户端之前进行更改的最后一个位置。
Nest中各类组件使用及请求链路
适用场景:

异常过滤器主要用于异常处理,提供友好的异常提示信息

1、全局过滤器

1、定义全局过滤器1

import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';

@Catch(HttpException)
export class GlobalHttpExceptionFilter implements ExceptionFilter {
    catch(exception: HttpException, host: ArgumentsHost) {
        console.log("全局过滤器 GlobalHttpExceptionFilter")

        const ctx = host.switchToHttp();
        const response = ctx.getResponse<Response>();
        const request = ctx.getRequest<Request>();
        const status = exception.getStatus();

        response
            .status(status)
            .json({
                statusCode: status,
                timestamp: new Date().toISOString(),
                path: request.url,
                from:"GlobalHttpExceptionFilter"
            });
    }
}

2、定义全局过滤器2

import {
    ExceptionFilter,
    Catch,
    ArgumentsHost,
    HttpException,
    HttpStatus,
} from '@nestjs/common';

@Catch()
export class GlobalAllExceptionFilter implements ExceptionFilter {
    catch(exception: unknown, host: ArgumentsHost) {
        console.log("全局过滤器 GlobalAllExceptionFilter")

        const ctx = host.switchToHttp();
        const response = ctx.getResponse();
        const request = ctx.getRequest();

        const status =
            exception instanceof HttpException
                ? exception.getStatus()
                : HttpStatus.INTERNAL_SERVER_ERROR;

        response.status(status).json({
            statusCode: status,
            timestamp: new Date().toISOString(),
            path: request.url,
            from:"GlobalAllExceptionFilter"
        });
    }
}

3、注册全局过滤器1和2

import {NestFactory} from '@nestjs/core';
import {AppModule} from './app.module';
import {markMiddleware} from "./middleware/mark.middleware";
import {GlobalHttpExceptionFilter} from "./filter/GlobalHttpExceptionFilter";
import {GlobalAllExceptionFilter} from "./filter/GlobalAllExceptionFilter";
import {GlobalLoggingInterceptor} from "./interceptor/GlobalLogging.interceptor";
import {AuthGuard} from "./guard/AuthGuard";
import {GlobalValidationPipe} from "./pipe/GlobalValidate.pipe";

async function bootstrap() {
    const app = await NestFactory.create(AppModule);
    app.useGlobalPipes(new GlobalValidationPipe())
    app.useGlobalGuards(new AuthGuard())
    app.useGlobalInterceptors(new GlobalLoggingInterceptor())
    app.useGlobalFilters(new GlobalHttpExceptionFilter())
    app.useGlobalFilters(new GlobalAllExceptionFilter())

    app.use(markMiddleware)
    await app.listen(3001);
}

bootstrap();

Nest中各类组件使用及请求链路
4、定义多个全局过滤器的执行顺序为
执行后注册的一个
Nest中各类组件使用及请求链路

2、局部过滤器

1、定义局部过滤器ControllerAllExceptionFilter

import {
    ExceptionFilter,
    Catch,
    ArgumentsHost,
    HttpException,
    HttpStatus,
} from '@nestjs/common';

@Catch()
export class ControllerAllExceptionFilter implements ExceptionFilter {
    catch(exception: unknown, host: ArgumentsHost) {
        console.log("控制层异常过滤器 ControllerAllExceptionFilter")

        const ctx = host.switchToHttp();
        const response = ctx.getResponse();
        const request = ctx.getRequest();

        const status =
            exception instanceof HttpException
                ? exception.getStatus()
                : HttpStatus.INTERNAL_SERVER_ERROR;

        response.status(status).json({
            statusCode: status,
            timestamp: new Date().toISOString(),
            path: request.url,
            from:"ControllerAllExceptionFilter"
        });
    }
}

2、定义局部过滤器ControllerHttpExceptionFilter

import {
    ExceptionFilter,
    Catch,
    ArgumentsHost,
    HttpException,
    HttpStatus,
} from '@nestjs/common';

@Catch()
export class ControllerHttpExceptionFilter implements ExceptionFilter {
    catch(exception: unknown, host: ArgumentsHost) {
        console.log("控制层异常过滤器 ControllerHttpExceptionFilter")

        const ctx = host.switchToHttp();
        const response = ctx.getResponse();
        const request = ctx.getRequest();

        const status =
            exception instanceof HttpException
                ? exception.getStatus()
                : HttpStatus.INTERNAL_SERVER_ERROR;

        response.status(status).json({
            statusCode: status,
            timestamp: new Date().toISOString(),
            path: request.url,
            from:"ControllerHttpExceptionFilter"
        });
    }
}

3、注册局部过滤器
Nest中各类组件使用及请求链路
4、局部过滤器执行顺序
注册多个局部(控制层、路由层)过滤器时,谁先注册,先执行谁
Nest中各类组件使用及请求链路

3、过滤器执行顺序

1、定义多个过滤器时,只会执行一个
2、按优先级执行:路由>控制器>全局
3、多个全局控制器,后注册限制性
4、多个局部控制器,先注册先执行
5、由于是发生异常引起执行过滤器,之后的流程中断

3、拦截器

拦截器可以在调用路由处理程序之前之后访问响应/请求。
Nest中各类组件使用及请求链路
1、功能
拦截器具有一系列有用的功能,这些功能受面向切面编程(AOP)技术的启发。它们可以:

  • 在函数执行之前/之后绑定额外的逻辑
  • 转换从函数返回的结果
  • 转换从函数抛出的异常
  • 扩展基本函数行为

2、常见应用场景

1、日志记录 :记录请求信息的日志
2、性能检测:检测方法的执行时间

1、全局拦截器

1、定义全局拦截器

import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class GlobalLoggingInterceptor implements NestInterceptor {
    intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        console.log('全局拦截器 GlobalLoggingInterceptor Before...');

        const now = Date.now();
        return next
            .handle()
            .pipe(
                tap(() => console.log(`全局拦截器 After... ${Date.now() - now}ms`)),
            );
    }
}

2、注册全局拦截器
Nest中各类组件使用及请求链路

2、局部拦截器

1、注册局部拦截器

import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
    intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        console.log('控制器层拦截器 LoggingInterceptor Before...');

        const now = Date.now();
        return next
            .handle()
            .pipe(
                tap(() => console.log(`控制器层拦截器 After... ${Date.now() - now}ms`)),
                //tap() 运算符,该运算符在可观察序列的正常或异常终止时调用函数。
            );
    }
}

2、注册局部拦截器
Nest中各类组件使用及请求链路

3、执行顺序

1、next.handle之前:全局- >控制层->路由层
2、next.handle之后:路由层- >控制层->全局
Nest中各类组件使用及请求链路

4、守卫

Nest中各类组件使用及请求链路
适用场景

  • 授权,假设用户是经过身份验证的(因此,请求头附加了一个token)。它将提取和验证token,并使用提取的信息来确定请求是否可以继续。
  • 角色认证,允许具有特定角色的用户访问

守卫在每个中间件之后执行,但在任何拦截器或管道之前执行。

1、全局守卫

1、定义全局守卫

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';

@Injectable()
export class AuthGuard implements CanActivate {
    canActivate(
        context: ExecutionContext,
    ): boolean | Promise<boolean> | Observable<boolean> {
        // const request = context.switchToHttp().getRequest();
        console.log("全局守卫 Global AuthGuard")
        return true
    }
}

2、注册全局守卫
Nest中各类组件使用及请求链路

2、局部守卫

1、定义局部守卫

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';

@Injectable()
export class RolesGuard implements CanActivate {
    canActivate(
        context: ExecutionContext,
    ): boolean | Promise<boolean> | Observable<boolean> {
        console.log("控制层守卫 RolesGuard")
        return true;
    }
}

2、注册局部守卫
Nest中各类组件使用及请求链路

3、执行顺序

Nest中各类组件使用及请求链路

5、管道

Nest中各类组件使用及请求链路
管道有两个类型:

  • 转换:管道将输入数据转换为所需的数据输出
  • 验证:对输入数据进行验证,如果验证成功继续传递; 验证失败则抛出异常;

管道在异常区域内运行。这意味着当抛出异常时,它们由核心异常处理程序和应用于当前上下文的 异常过滤器 处理。当在 Pipe 中发生异常,controller 不会继续执行任何方法。

1、全局管道

1、定义全局管道

import {PipeTransform, Injectable, ArgumentMetadata, BadRequestException} from '@nestjs/common';
import {plainToClass} from "class-transformer";
import {validate} from "class-validator";

@Injectable()
export class GlobalValidationPipe implements PipeTransform {
    /*
    value 是当前处理的参数,而 metadata 是其元数据。元数据对象包含一些属性:
    export interface ArgumentMetadata {
     type: 'body' | 'query' | 'param' | 'custom';
     metatype?: Type<unknown>;
     data?: string;
 }*/

    async transform(value: any, { metatype }: ArgumentMetadata) {
        console.log("全局管道 global ValidationPipe")
        if (!metatype || !this.toValidate(metatype)) {
            return value;
        }
        const object = plainToClass(metatype, value);
        const errors = await validate(object);
        if (errors.length > 0) {
            throw new BadRequestException('全局管道 Validation failed');
        }
        return value;
    }

    //当验证类型不是 JavaScript 的数据类型时,跳过验证。
    private toValidate(metatype: Function): boolean {
        const types: Function[] = [String, Boolean, Number, Array, Object];
        return !types.includes(metatype);
    }
}

2、注册全局管道
Nest中各类组件使用及请求链路

2、局部管道

1、定义局部管道

import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';

@Injectable()
export class ParseIntPipe implements PipeTransform<string, number> {
    transform(value: string, metadata: ArgumentMetadata): number {
        console.log("路由参数管道 ParseIntPipe")

        const val = parseInt(value, 10);
        if (isNaN(val)) {
            throw new BadRequestException('路由参数管道 Validation failed');
        }
        return val;
    }
}

2、注册局部管道
Nest中各类组件使用及请求链路

3、执行顺序

Nest中各类组件使用及请求链路

3、各组件间请求链路

即一个请求的生命周期

Nest中各类组件使用及请求链路

总结

1、nest中的组件
  • 中间件(Middleware)
  • 异常过滤器(Exception filters)
  • 拦截器(Interceptors)
  • 守卫(Guards)
  • 管道(Pipes)
2、请求的生命周期如下

1、中间件

全局绑定的中间件(有多个就按注册顺序执行)->模块绑定的中间件(有多个就按注册顺序执行)

2、守卫

全局守卫->控制层守卫->路由守卫

3、拦截器(next.handle之前)

全局拦截器(route.handle之前)->控制器层拦截器 (route.handle之前)->路由拦截器 (route.handle之前)

4、管道

全局管道->控制器管道->路由管道->路由参数管道

5、控制器(方法处理器)

6、服务(provider)

7、拦截器(next.handle之后)

路由拦截器(route.handle之后)->控制器拦截器 (route.handle之后)->全局拦截器 (route.handle之后)

8、异常过滤器

按优先级执行:路由>控制器>全局Nest中各类组件使用及请求链路

上一篇:c#-NEST弹性搜索中的Lambda查询具有过滤器和值的数组


下一篇:CodeGo.net>如何在弹性搜索中使用NEST(1.8)索引字符串数组?