nest入门教程

Nest是构建高效,可扩展的 Node.js Web 应用程序的框架

大纲

起步

安装nestjs

1
2
$ npm i -g @nestjs/cli

创建nest项目

1
$ nest new project-name
  • 目录如下:
    1
    2
    3
    4
    app.controller.ts // 控制器
    app.module.ts // 根模块
    app.service.ts // 服务
    main.ts // 入口文件
  • 入口文件
    1
    2
    3
    4
    5
    6
    7
    8
    /** main.ts */
    import { NestFactory } from '@nest/core';
    import { AppModule } from './app.module';
    async function bootstrap() {
    const app = await NestFactory.create(AppModule);
    await app.listen(3000);
    }
    bootstrap();
  • 运行应用程序
    1
    $ npm run start

控制器(Controller)

路由 + 请求(Request)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 请求路径: /api/user-list
import { Controller, Get } from '@nestjs/common';
import { Request } from 'express';
@Controller('/api')
export class CatsController {
@Get('/user-list') // @Put @Delete @Patch @Options @Head @All
// @Req 获取所有的请求参数, 包括header头信息
// @Param 获取查询参数 如:/api/user/123
// @Body 获取post的请求体
// @Query 获取url上的查询参数
findAll(@Req() request: Request): string {
return 'This action returns all users';
}
}

请求方法

GET
POST
PUT
DELETE
PATCH
ALL
OPTIONS
HEAD

Controller常用装饰器

1
2
3
4
5
6
7
8
// 请求相关装饰器
@Request @Response @Next
@Session @Param @Body
@Query @Headers @Ip @HostParam

// http方法相应装饰器
@HttpCode @Put @Delete @Patch @Options @Head @All

  • 定义DTO
    1
    2
    3
    4
    5
    export class CreateCatDto {
    readonly name: string;
    readonly age: number;
    readonly breed: string;
    }

完整示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/* cats.controller.ts */
import { Controller, Get, Query, Post, Body, Put, Param, Delete } from '@nestjs/common';
import { CreateCatDto, UpdateCatDto, ListAllEntities } from './dto';
@Controller('cats')
export class CatsController {
@Post()
create(@Body() createCatDto: CreateCatDto) {
return 'This action adds a new cat';
}
@Get()
findAll(@Query() query: ListAllEntities) {
return `This action returns all cats (limit: ${query.limit} items)`;
}
@Get(':id')
findOne(@Param('id') id: string) {
return `This action returns a #${id} cat`;
}
@Put(':id')
update(@Param('id') id: string, @Body() updateCatDto: UpdateCatDto) {
return `This action updates a #${id} cat`;
}
@Delete(':id')
remove(@Param('id') id: string) {
return `This action removes a #${id} cat`;
}
}

类库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* cats.controller.ts */
import { Controller, Get, Post, Res, HttpStatus } from '@nestjs/common';
import { Response } from 'express';
@Controller('cats')
export class CatsController {
@Post()
create(@Res() res: Response) {
res.status(HttpStatus.CREATED).send();
}
@Get()
findAll(@Res() res: Response) {
res.status(HttpStatus.OK).json([]);
}
}

提供者(Provider)+ Service

  • 服务
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import { Injectable } from '@nestjs/common';
    import { Cat } from './interfaces/cat.interface';

    @Injectable() // 注入依赖
    export class CatsService<T> {
    // 实例注入
    constructor(private catsService: CatsService) {}
    // 属性注入
    @Inject('HTTP_OPTIONS')
    private readonly httpClient: T;
    private readonly cats: Cat[] = [];
    create(cat: Cat) {
    this.cats.push(cat);
    }
    findAll(): Cat[] {
    return this.cats;
    }
    }
  • 可选提供者
    1
    2
    3
    4
    5
    6
    7
    import { Injectable, Optional, Inject } from '@nestjs/common';
    @Injectable()
    export class HttpService<T> {
    constructor(
    @Optional() @Inject('HTTP_OPTIONS') private readonly httpClient: T
    ) {}
    }

模块(Module)

组织应用结构

1
2
3
4
5
6
@module({
controllers: [CatsController],
providers:[CatsService],
imports: [],
exports: []
})

命令行

1
2
3
$ nest g module cats
$ nest g controller cats
$ nest g service cats

模块

1
@Module @DynamicModule @Controller @Service @Global

动态模块???

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/** DatabaseModule.module.ts */
import { Module, DynamicModule } from '@nestjs/common';
import { CreateDatabaseProviders } from './database.providers';
import { Connection } from './connection.provider';
@Module({
providers: [Connection],
})
export class DatabaseModule {
static forRoot(entities=[], options?): DynamicModule {
const providers = CreateDatabaseProviders(options, entities);
return {
module: DatabaseModule,
providers: providers,
exports: providers
}
}
}

/** App.module.ts */
import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { User } from './users/entities/user.entity';
@Module({
imports: [DatabaseModule.forRoot([User])],
exports: [DatabaseModule],
})
export class AppModule {}

中间件

  • 主要执行以下任务:

    • 执行任何代码
    • 对请求和响应对象进行更改
    • 结束请求-响应周期
    • 调用堆栈中的下一个中间件函数
    • 如果当前的中间件函数没有结束请求-响应周期, 它必须调用 next() 将控制传递给下一个中间件函数。否则, 请求将被挂起
    • 可以通过constructor注入依赖
  • 定义中间件

1
2
3
4
5
6
7
8
9
10
/** logger.middleware.ts */
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('Request...');
next();
}
}
  • 应用中间件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    /** 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 {
    configure(consumer: MiddlewareConsumer) {
    consumer
    .apply(LoggerMiddleware, cors(), cors1()) // 应用多个中间件
    // .exclue(
    // { path: 'cats', method: RequestMethod.GET },
    // { path: 'cats', method: RequestMethod.POST }
    // )
    .forRoutes({
    path: 'cats',
    method: RequestMethod.GET
    });
    }
    }
  • 全局中间件
    1
    2
    3
    const app = await NestFactory.create(AppModule);
    app.use(logger);
    await app.listen(3000);

异常过滤器

  • 基础异常类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /** cats.controller.ts */
    @Get()
    async findAll() {
    // HttpException第一个参数支持字符串和对象
    throw new HttpException('Forbidden', HttpCode.FORBIDDEN);
    }

    @Get()
    async findAll2() {
    throw new HttpException({
    status: HttpCode.FORBIDDEN,
    error: 'This is a custom message',
    }, HttpStatus.FORBIDDEN)
    }
  • 自定义异常

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /** forbidden.exception.ts */
    export class ForbiddenException extends HttpException {
    constructor() {
    super('Forbidden', HttpStatus.FORBIDDEN)
    }
    }
    /** 使用自定义异常 */
    @Get()
    async findAll() {
    throw new ForbiddenException();
    }
  • 内置异常
    BadRequestException
    UnauthorizedException
    NotFoundException
    ForbiddenException
    NotAcceptableException
    RequestTimeoutException
    ConflictException
    GoneException
    PayloadTooLargeException
    UnsupportedMediaTypeException
    UnprocessableException
    InternalServerErrorException
    NotImplementedException
    BadGatewayException
    ServiceUnavailableException
    GatewayTimeoutException

  • 异常过滤器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
    import { Request, Response } from 'express';
    @Catch(HttpException)
    export class HttpExceptionFilter implements ExceptionFilter {
    catch(exception: HttpException, host: ArgumentsHost) {
    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,
    });
    }
    }
  • 绑定过滤器

    1
    2
    3
    4
    5
    @Post()
    @UseFilters(new HttpExceptionFilter())
    async create(@Body() createCatDto: CreateCatDto) {
    throw new ForbiddenException();
    }
  • 全局过滤器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import { Module } from '@nestjs/common';
    import { APP_FILTER } from '@nestjs/core';
    @Module({
    providers: [
    {
    provide: APP_FILTER,
    useClass: HttpExceptionFilter,
    },
    ],
    })
    export class AppModule {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
HttpStatus,
} from '@nestjs/common';
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
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,
});
}
}

管道

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

  • 内置管道
    ValidationPipe
    ParseIntPipe
    ParseBoolPipe
    ParseArrayPipe
    ParseUUIDPipe
    DefaultValuePipe

  • 自定义管道

    1
    2
    3
    4
    5
    6
    7
    import { PipeTransform, Injectable, ArgumentMetadata } from '@nestjs/common';
    @Injectable()
    export class ValidationPipe implements PipeTransform {
    transform(value: any, metadata: ArgumentMetadata) {
    return value;
    }
    }
  • 对象结构验证

    1
    2
    $ npm install --save @hapi/joi
    $ npm install --save-dev @types/hapi__joi
  • 验证管道

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
    import { ObjectSchema } from '@hapi/joi';
    @Injectable()
    export class JoiValidationPipe implements PipeTransform {
    constructor(private schema: ObjectSchema) {}
    transform(value: any, metadata: ArgumentMetadata) {
    const { error } = this.schema.validate(value);
    if (error) {
    throw new BadRequestException('Validation failed');
    }
    return value;
    }
    }
  • 绑定管道

    1
    2
    3
    4
    5
    @Post()
    @UsePipes(new JoiValidationPipe(createCatSchema))
    async create(@Body() createCatDto: CreateCatDto) {
    this.catsService.create(createCatDto);
    }
  • 类验证器
    npm i --save class-validator class-transformer

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import { IsString, IsInt } from 'class-validator';
    export class CreateCatDto {
    @IsString()
    name: string;
    @IsInt()
    age: number;
    @IsString()
    breed: string;
    }

类验证器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToClass } from 'class-transformer';
@Injectable()
export class ValidationPipe implements PipeTransform<any> {
async transform(value: any, { metatype }: ArgumentMetadata) {
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;
}
private toValidate(metatype: Function): boolean {
const types: Function[] = [String, Boolean, Number, Array, Object];
return !types.includes(metatype);
}
}
  • 全局管道

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import { Module } from '@nestjs/common';
    import { APP_PIPE } from '@nestjs/core';
    @Module({
    providers: [
    {
    provide: APP_PIPE,
    useClass: ValidationPipe
    }
    ]
    })
    export class AppModule {}
  • 转换管道

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
    @Injectable()
    export class ParseIntPipe implements PipeTransform<string, number> {
    transform(value: string, metadata: ArgumentMetadata): number {
    const val = parseInt(value, 10);
    if (isNaN(val)) {
    throw new BadRequestException('Validation failed');
    }
    return val;
    }
    }

守卫

├── 授权守卫
├── 基于角色认证
├── 绑定守卫

拦截器

├── 绑定拦截器
├── 响应映射
├── 异常映射

nest流程图

图片

控制器

配置请求路由(Get/Post)

1
2
3
4
5
6
7
8
9
10
11
12
13
@Controller('app')
export class AppController {
// get请求
@Get('/list')
list(): string {
return '我是get请求';
}
// post请求
@Post('/create')
create(): string {
return '我是post请求';
}
}

vscode调试node

(1)配置路径: 运行=>添加配置

图片
(2) 选择‘nodejs’

图片
(3) 调试成功

图片

步骤

(1)配置路径: 运行=>添加配置

(2) 选择‘nodejs’

(3) 调试成功

获取请求参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Controller('app')
export class AppController {
// 获取所有的参数
@Get('/all')
all(@Req() req: Request): string {
console.log(req);
return 'hello all';
}
// 获取动态参数
@Get('/param/:id')
getParams(@Param('id') id: number): string {
console.log(id);
return `获得参数id为${id}`;
}
// 获取请求体body
@Post('body')
getBody(@Body() req: object): object {
console.log(req);
return req;
}
// 获取url查询参数
@Get('query')
getQuery(@Query('name') name: string): string {
console.log(name);
return `获得参数name为${name}`;
}
// 获取请求头信息
@Get('header')
getHeader(@Headers() req: object): object {
console.log(req);
return req;
}
}

设置响应数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Controller('app')
export class AppController {
// 设置状态码
@Get('/httpCode')
@HttpCode(304)
getHttpCode() {
return 'hello getHttpCode';
}

// 设置header头
@Get('/header')
@Header('abc', 'xxx')
getHeaders() {
return 'hello getHeaders';
}

// 重定向
@Get('/redirect')
@Redirect('https://nestjs.com', 301)
getRedirect(): string {
return 'hello getRedirect';
}
}

调用服务方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
--------------------app.controller.ts----------------------

@Controller('app')
export class AppController {
constructor(private readonly appservice: AppService) {}
@Get('hello')
getHello(): string {
return this.appservice.getHello();
}
}

----------------------app.service.ts-------------------------
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}

共享模块(sharedModule)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
--------------------cats.module.ts-----------------
@Module({
controllers: [CatsController],
providers: [CatsService],
exports: [CatsService], // 在引入CatsModule时不需要显式注册服务
})
export class CatsModule {}

--------------------app.module.ts-----------------
@Module({
imports: [CatsModule],
controllers: [AppController],
providers: [AppService], // 不需要显式指定CatsService
})
export class AppModule {}

--------------------app.controller.ts-----------------
@Controller('app')
export class AppController {
constructor(private readonly catsService: CatsService) {} // 注入依赖
@Get('hello')
getHello(): string {
return this.catsService.getCats(); // 能直接调用catsService的方法
}
}

--------------------common.module.ts-----------------
@Global() // 全局模块
@Module({
providers: [CommonService],
controllers: [CommonController],
exports: [CommonService],
})
export class CommonModule {}

中间件(midddleware)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
--------------------logger.middleware.ts-----------------
// 函数中间件
export function LoggerMiddleware(req, res, next) {
console.log(`Global Logger Request...`);
next();
}
// class中间件
@Injectable()
export class Logger1Middleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
console.log('Logger1 Request...');
next();
}
}

--------------------main.ts----------------------
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(LoggerMiddleware); // 注册全局中间件
await app.listen(3000);
}
bootstrap();

--------------------app.module.ts-----------------
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
// 应用多个中间件
consumer
.apply(Logger1Middleware, Logger2Middleware, Logger3Middleware)
.forRoutes('/cats/global-fn-middleware');
}
}

异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
--------------------app.controller.ts-----------------
@Controller('app')
export class AppController {
constructor(private readonly catsService: CatsService) {}
@Get('custom-forbidden')
async customForbindden() {
// throw new HttpException('Forbidden111', HttpStatus.FORBIDDEN); // nest内置异常
throw new ForbiddenException();
}
}

--------------------forbidden.exception.ts-----------------
export class ForbiddenException extends HttpException {
constructor() {
super('custom Forbidden', HttpStatus.FORBIDDEN);
}
}

--------------------main.ts-----------------
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(LoggerMiddleware);
// app.useGlobalFilters(new HttpExceptionFilter()); // 注册全局异常
app.useGlobalFilters(new AllExceptionsFilter()); // 注册全局异常
await app.listen(3000);
}
bootstrap();

--------------------any-exception.filter.ts-----------------
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
// 指定处理某类一样
const status =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
console.log('AllExceptionsFilter');
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}


管道(pipe)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
--------------------any-exception.filter.ts-----------------
const Joi = require('joi');
const schema = Joi.object({
username: Joi.string()
.min(3)
.max(16)
.required(),
password: Joi.string()
})

@Controller()
export class AppController {
constructor(private readonly catsService: CatsService) { }
// 自定义管道
@Get('pipe/:id')
findOne(
@Param('id', new ParseIntPipe()) // 验证是否数字
id: number,
): string {
return `get id ${id} `;
}
// 对象验证(joi) https://joi.dev/api/?v=17.6.0
@Post('create')
@UsePipes(new JoiValidationPipe(schema)) // 对象验证
create(@Body() Body) {
return '表单创建成功!'
}
}

--------------------parse-int.pipe.ts-----------------
@Injectable()
export class ParseIntPipe implements PipeTransform<string> {
async transform(value: string, metadata: ArgumentMetadata) {
const val = parseInt(value, 10);
if (isNaN(val)) {
throw new BadRequestException('无效的值');
}
return val;
}
}

--------------------joi.validation.pipe.ts-----------------
@Injectable()
export class JoiValidationPipe implements PipeTransform {
constructor(private schema: Schema) {}
transform(value: any, metadata: ArgumentMetadata) {
console.log("JoiValidationPipe", value)
const { error } = this.schema.validate(value);
if (error) {
throw new BadRequestException('表单数据填写有误,请重新提交');
}
return value;
}
}

守卫(guard)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
--------------------app.controller.ts-----------------
@UseGuards(RolesGuard) // 注册守卫
// @UseInterceptors(Logging1Interceptor)
@Controller()
export class AppController {
constructor(private readonly catsService: CatsService) {}
// 守卫
@Post('/guards/create')
guards() {
return 'get guards';
}
}

--------------------roles.guard.ts-----------------
@Injectable()
export class RolesGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
console.log('RolesGuard_', request.body);
// validateForm(request.body); // 验证表单内容
return true;
}
}

拦截器(interceptor)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
--------------------app.controller.ts-----------------
@UseInterceptors(Logging1Interceptor) // 注册拦截器到控制器
@Controller()
export class AppController {
constructor(private readonly catsService: CatsService) {}
// 拦截器-异常映射
@Get('interceptor-exception')
@UseInterceptors(new ErrorsInterceptor()) // 注册拦截器到方法
exception(): string {
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
return 'get interceptor-exception';
}

// 拦截器-响应映射
@Post('interceptor-response')
@UseInterceptors(new TransformInterceptor()) // 注册拦截器到方法
response(): object {
return {
errCode: -10000,
msg: '购买失败',
};
}
// 绑定拦截器-三种方式
@Get('interceptor')
getInterceptor(): string {
return 'get Interceptor';
}
}

--------------------logging1.interceptor.ts-----------------
@Injectable()
export class Logging1Interceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
console.log('Before Logging-1-Interceptor...');
const now = Date.now();
return next
.handle()
.pipe(
tap(() => console.log(`After Logging-1-Interceptor... ${Date.now() - now}ms`)),
);
}
}

--------------------exception.interceptor.ts-----------------
@Injectable()
export class ErrorsInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
console.log('ErrorsInterceptor__');
return next
.handle()
.pipe(catchError((err) => throwError(new BadGatewayException())));
}
}

--------------------transform.interceptor.ts-----------------
@Injectable()
export class TransformInterceptor<T>
implements NestInterceptor<T, Response<T>>
{
intercept(
context: ExecutionContext,
next: CallHandler,
): Observable<Response<T>> {
console.log('TransformInterceptor');
return next.handle().pipe(
map((data) => {
console.log(data);
typeof data === 'object' ? (data['detail'] = '库存不足') : '';
return data;
}),
);
}
}


async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 注册全局中间件
// app.use(LoggerMiddleware);

// 注册全局异常
// app.useGlobalFilters(new HttpExceptionFilter());
// app.useGlobalFilters(new AllExceptionsFilter());

// 注册全局守卫
// app.useGlobalGuards(new AuthGlobalGuard());

// 注册全局拦截器
// app.useGlobalInterceptors(new Logging2Interceptor())
app.useGlobalInterceptors(new TransformInterceptor());

await app.listen(3000);
}
bootstrap();

nestjs核心模块

1