ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-02-03 16:30:47  阅读:299  来源: 互联网

标签:拦截器 const Nest 中间件 过滤器 链路 组件 import 全局


1、Nest中有什么组件

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

2、各组件主要用法

1、中间件

仅在调用路由处理程序之前调用中间件。可以访问响应对象,但是没有路由处理程序的结果。
在这里插入图片描述

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

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

适用场景:

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

2、日志记录

3、请求监控

1、全局中间件

1、定义全局中间件:

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

在这里插入图片描述
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();

在这里插入图片描述

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();
    }
}

在这里插入图片描述
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)
    }
}

在这里插入图片描述

3、中间件执行顺序

全局绑定的中间件(有多个就按注册顺序执行) -> 模块绑定的中间件(有多个就按注册顺序执行)
在这里插入图片描述

2、异常过滤器

异常过滤器在路由处理程序之后和拦截器之后调用。它们是在响应到达客户端之前进行更改的最后一个位置。
在这里插入图片描述
适用场景:

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

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();

在这里插入图片描述
4、定义多个全局过滤器的执行顺序为
执行后注册的一个
在这里插入图片描述

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、注册局部过滤器
在这里插入图片描述
4、局部过滤器执行顺序
注册多个局部(控制层、路由层)过滤器时,谁先注册,先执行谁
在这里插入图片描述

3、过滤器执行顺序

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

3、拦截器

拦截器可以在调用路由处理程序之前之后访问响应/请求。
在这里插入图片描述
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、注册全局拦截器
在这里插入图片描述

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、注册局部拦截器
在这里插入图片描述

3、执行顺序

1、next.handle之前:全局- >控制层->路由层
2、next.handle之后:路由层- >控制层->全局
在这里插入图片描述

4、守卫

在这里插入图片描述
适用场景

  • 授权,假设用户是经过身份验证的(因此,请求头附加了一个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、注册全局守卫
在这里插入图片描述

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、注册局部守卫
在这里插入图片描述

3、执行顺序

在这里插入图片描述

5、管道

在这里插入图片描述
管道有两个类型:

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

管道在异常区域内运行。这意味着当抛出异常时,它们由核心异常处理程序和应用于当前上下文的 异常过滤器 处理。当在 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、注册全局管道
在这里插入图片描述

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、注册局部管道
在这里插入图片描述

3、执行顺序

在这里插入图片描述

3、各组件间请求链路

即一个请求的生命周期

在这里插入图片描述

总结

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、异常过滤器

按优先级执行:路由>控制器>全局在这里插入图片描述

标签:拦截器,const,Nest,中间件,过滤器,链路,组件,import,全局
来源: https://blog.csdn.net/weixin_42719656/article/details/113523164

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有