nest.js框架使用

1、安装

npm i -g @nestjs/cli 全局安装cli

nest new pro-name 创建项目

2、指令

nest new pro-name 全局命令:创建项目

nest -h 代码指令集列表

nest g mo login --no-spec 快速创建login module 不创建测试文件 --no-spec

nest g s login 快速创建login service

nest g co login 快速创建login controller

nest g res user 快速创建user crud模板

3、控制器 Controller

@Controller 后接请求路由名称 不写即为根路由

@Post post请求 后接请求路由名称 不写即为controller默认路由

@Get / @Patch /@Delete 同理

@Get(':id') get请求 @Param形式接动态值

@Body 表示为body形式接参 @Param 表示为param形式接参 @query表示为query形式接参

4、模块 Module 使用

1、单个模块使用

引入自身Controller组件和Service业务组件

2、多模块依赖引入

在自身模块组件引入其它模块组件即可使用其它依赖模块功能

2、其它模块业务引用

5、动态模块

NestJS 社区遵循以下命名规范:

register:每次使用时配置,多次导入会创建多个实例

forRoot:全局配置一次(通常用于整个应用)

forFeature:特性配置,通常配合 forRoot() 使用

js 复制代码
// config.module.ts
import { DynamicModule, Module } from '@nestjs/common';
import { ConfigService } from './config.service';

@Module({})
export class ConfigModule {
  static register(options: { folder: string }): DynamicModule {
    return {
      module: ConfigModule,
      providers: [
        {
          provide: 'CONFIG_OPTIONS',
          useValue: options,
        },
        ConfigService,
      ],
      exports: [ConfigService],
    };
  }
}

// config.service.ts
import { Inject, Injectable } from '@nestjs/common';

@Injectable()
export class ConfigService {
  constructor(@Inject('CONFIG_OPTIONS') private options: { folder: string }) {}
  
  getFolder(): string {
    return this.options.folder;
  }
}

// app.module.ts
@Module({
  imports: [
    ConfigModule.register({ folder: './config' })
  ],
})
export class AppModule {}

6、服务提供者

1、简化版本

js 复制代码
// user.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class UserService {
  private users = [
    { id: 1, name: 'Alice' },
    { id: 2, name: 'Bob' },
  ];

  findAll() {
    return this.users;
  }

  findOne(id: number) {
    return this.users.find(user => user.id === id);
  }
}

// user.controller.ts
import { Controller, Get } from '@nestjs/common';
import { UserService } from './user.service';

@Controller('users')
export class UserController {
  constructor(private userService: UserService) {}
  
  @Get()
  getUsers() {
    return this.userService.findAll();
  }
}

2、使用 useClass

js 复制代码
// app.module.ts
@Module({
  providers: [
    UserService,  // 简写形式,等同于 { provide: UserService, useClass: UserService }
  ],
})

3、使用自定义 Token

js 复制代码
// 使用字符串作为 Token
@Module({
  providers: [
    {
      provide: 'USER_SERVICE',
      useClass: UserService,
    },
  ],
})
export class AppModule {}

// 在控制器中使用
@Controller('users')
export class UserController {
  constructor(@Inject('USER_SERVICE') private userService: UserService) {}
}

4、使用 useValue(常量值)

js 复制代码
@Module({
  providers: [
    {
      provide: 'APP_NAME',
      useValue: 'My NestJS App',
    },
    {
      provide: 'CONFIG',
      useValue: {
        apiUrl: 'https://api.example.com',
        timeout: 5000,
      },
    },
  ],
})

7、守卫

守卫是一个使用 @Injectable() 装饰器的类,实现了 CanActivate 接口。它负责决定请求是否被处理,在请求到达路由处理器之前执行;守卫是实现授权和权限控制的核心功能

创建守卫

js 复制代码
// auth.guard.ts
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();
    const token = request.headers.authorization;
    
    // 简单的 token 验证逻辑
    if (token === 'valid-token') {
      return true;
    }
    return false;
  }
}

使用守卫

js 复制代码
// 控制器级别
@Controller('users')
@UseGuards(AuthGuard)
export class UsersController {
  @Get()
  findAll() {
    return '所有用户需要认证';
  }
}

// 方法级别
@Controller('users')
export class UsersController {
  @Get()
  @UseGuards(AuthGuard)
  findAll() {
    return '这个接口需要认证';
  }
  
  @Get('public')
  getPublic() {
    return '这个接口不需要认证';
  }
}
// 全局级别
// main.ts 或 app.module.ts
app.useGlobalGuards(new AuthGuard());

8、异常过滤器

异常过滤器负责捕获应用程序中抛出的异常,并将它们转换为统一的、友好的 HTTP 响应。它们可以控制响应的结构和内容

特点:

捕获全局或特定路由的异常

自定义异常响应格式

添加日志记录

统一错误处理逻辑

1、内置异常

js 复制代码
import { 
  BadRequestException,
  UnauthorizedException,
  ForbiddenException,
  NotFoundException,
  ConflictException,
  InternalServerErrorException,
  ServiceUnavailableException,
  HttpException,
  HttpStatus
} from '@nestjs/common';

// 使用示例
throw new BadRequestException('无效的用户数据');
throw new UnauthorizedException('请先登录');
throw new NotFoundException('用户不存在');
throw new ForbiddenException('权限不足');
throw new HttpException('自定义错误', HttpStatus.I_AM_A_TEAPOT);

2、创建自定义异常

js 复制代码
// http-exception.filter.ts
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();
    const exceptionResponse = exception.getResponse();

    response
      .status(status)
      .json({
        statusCode: status,
        timestamp: new Date().toISOString(),
        path: request.url,
        method: request.method,
        message: typeof exceptionResponse === 'string' 
          ? exceptionResponse 
          : exceptionResponse['message'],
        error: typeof exceptionResponse === 'string'
          ? exception.message
          : exceptionResponse['error'],
      });
  }
}

3、使用自定义异常

js 复制代码
// 方法级别
@Controller('users')
export class UsersController {
  @Get(':id')
  @UseFilters(HttpExceptionFilter)
  async findOne(@Param('id') id: string) {
    const user = await this.userService.findOne(id);
    if (!user) {
      throw new NotFoundException('用户不存在');
    }
    return user;
  }
}

// 控制器级别
@Controller('users')
@UseFilters(HttpExceptionFilter)
export class UsersController {
  // 所有方法都会使用这个过滤器
}
// 全局级别
// main.ts
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalFilters(new HttpExceptionFilter());
  await app.listen(3000);
}

9、管道

管道(Pipes),它是用于数据转换和验证的核心功能(执行时机:在中间件之后、守卫之前、路由处理器之前执行)

功能:

转换(Transformation):将输入数据转换为所需的格式(如字符串转数字)

验证(Validation):评估输入数据的有效性,如果无效抛出异常

1、简单自定义管道应用

js 复制代码
// uppercase.pipe.ts
import { PipeTransform, Injectable, ArgumentMetadata } from '@nestjs/common';

@Injectable()
export class UpperCasePipe implements PipeTransform {
  transform(value: any, metadata: ArgumentMetadata) {
    if (typeof value === 'string') {
      return value.toUpperCase();
    }
    return value;
  }
}

// 使用
@Controller('users')
export class UsersController {
  @Post()
  create(@Body('name', UpperCasePipe) name: string) {
    // name 自动转换为大写
    return { name };
  }
}

2、内置管道及应用

js 复制代码
// NestJS 提供了多个内置管道
import {
  ValidationPipe,
  ParseIntPipe,
  ParseFloatPipe,
  ParseBoolPipe,
  ParseArrayPipe,
  ParseUUIDPipe,
  ParseEnumPipe,
  DefaultValuePipe,
  ParseFilePipe,
  FileTypeValidator,
  MaxFileSizeValidator,
} from '@nestjs/common';

@Controller('users')
export class UsersController {
  // 解析整数
  @Get(':id')
  findOne(@Param('id', ParseIntPipe) id: number) {
    // id 现在是 number 类型
    return this.userService.findOne(id);
  }

  // 解析 UUID
  @Get('uuid/:uuid')
  findByUuid(@Param('uuid', ParseUUIDPipe) uuid: string) {
    return this.userService.findByUuid(uuid);
  }

  // 解析布尔值
  @Get()
  findAll(@Query('active', ParseBoolPipe) active: boolean) {
    return this.userService.findAll(active);
  }

  // 解析数组
  @Get('filter')
  filter(@Query('ids', ParseArrayPipe) ids: number[]) {
    // GET /users/filter?ids=1,2,3 → ids = [1,2,3]
    return this.userService.filter(ids);
  }

  // 枚举验证
  @Post()
  create(@Body('role', new ParseEnumPipe(RoleEnum)) role: RoleEnum) {
    return this.userService.create(role);
  }

  // 默认值
  @Get()
  getUsers(
    @Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
    @Query('limit', new DefaultValuePipe(10), ParseIntPipe) limit: number,
  ) {
    return this.userService.getUsers(page, limit);
  }
}

3、ValidationPipe管道(数据验证)

js 复制代码
// main.ts
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  
  app.useGlobalPipes(new ValidationPipe({
    whitelist: true,              // 自动删除非白名单属性
    forbidNonWhitelisted: true,   // 存在非白名单属性时抛出错误
    transform: true,              // 自动转换类型
    transformOptions: {
      enableImplicitConversion: true, // 隐式类型转换
    },
    disableErrorMessages: false,   // 是否禁用详细错误消息
    skipMissingProperties: false,  // 是否跳过缺失属性
    validationError: {
      target: false,               // 是否在错误中包含目标对象
      value: false,                // 是否在错误中包含值
    },
  }));
  
  await app.listen(3000);
}

// DTO 定义
// create-user.dto.ts
import {
  IsString,
  IsEmail,
  IsInt,
  Min,
  Max,
  IsOptional,
  IsPhoneNumber,
  IsUrl,
  IsDate,
  IsEnum,
  IsArray,
  IsBoolean,
  MinLength,
  MaxLength,
  Matches,
  ValidateNested,
  ArrayMinSize,
  ArrayMaxSize,
  IsPositive,
  IsNegative,
  IsNotEmpty,
  IsDefined,
} from 'class-validator';
import { Type } from 'class-transformer';
import { ApiProperty } from '@nestjs/swagger';

export enum UserRole {
  ADMIN = 'admin',
  USER = 'user',
  GUEST = 'guest',
}

export class ProfileDto {
  @IsString()
  @MinLength(2)
  nickname: string;

  @IsUrl()
  avatar: string;

  @IsOptional()
  @IsString()
  bio?: string;
}

export class CreateUserDto {
  @ApiProperty({ description: '用户名', example: 'john_doe' })
  @IsString()
  @MinLength(3, { message: '用户名至少3个字符' })
  @MaxLength(20, { message: '用户名最多20个字符' })
  @Matches(/^[a-zA-Z0-9_]+$/, { message: '用户名只能包含字母、数字和下划线' })
  username: string;

  @ApiProperty({ description: '邮箱', example: 'john@example.com' })
  @IsEmail({}, { message: '请提供有效的邮箱地址' })
  email: string;

  @ApiProperty({ description: '密码', example: 'StrongP@ss123' })
  @IsString()
  @MinLength(8)
  @MaxLength(32)
  @Matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])/, {
    message: '密码必须包含大小写字母、数字和特殊字符',
  })
  password: string;

  @ApiProperty({ description: '年龄', example: 25, required: false })
  @IsOptional()
  @IsInt()
  @Min(18)
  @Max(120)
  @IsPositive()
  age?: number;

  @ApiProperty({ description: '手机号', example: '+8613800000000' })
  @IsPhoneNumber('CN', { message: '请提供有效的中国手机号' })
  phone: string;

  @ApiProperty({ description: '角色', enum: UserRole })
  @IsEnum(UserRole)
  role: UserRole;

  @ApiProperty({ description: '兴趣', type: [String] })
  @IsArray()
  @ArrayMinSize(1)
  @ArrayMaxSize(10)
  @IsString({ each: true })
  hobbies: string[];

  @ApiProperty({ description: '是否激活' })
  @IsBoolean()
  isActive: boolean;

  @ApiProperty({ description: '生日' })
  @IsDate()
  @Type(() => Date)
  birthday: Date;

  @ApiProperty({ description: '个人资料' })
  @ValidateNested()
  @Type(() => ProfileDto)
  profile: ProfileDto;

  @ApiProperty({ description: '注册时间' })
  @IsDate()
  @Type(() => Date)
  @IsOptional()
  createdAt?: Date;
}

10、中间件

1、创建模块中间件

js 复制代码
// 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(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
    next();
  }
}

2、应用模块中间件(全路由)

js 复制代码
// app.module.ts
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './logger.middleware';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes('*'); // 所有路由
  }
}

3、应用模块中间件(指定路由)

js 复制代码
// app.module.ts
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes(
        { path: 'users', method: RequestMethod.GET },  // 特定路径和方法
        { path: 'posts', method: RequestMethod.ALL },   // 所有方法
        'products',                                      // 字符串路径
      );
  }
}

4、应用模块中间(指定控制器)

js 复制代码
// app.module.ts
import { UsersController } from './users/users.controller';

export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes(UsersController); // 整个控制器
  }
}
相关推荐
aiguangyuan4 个月前
Nest 与 TypeORM Cli 集成
node·后端开发·nest
代码哈士奇1 年前
认识中间件-以及两个简单的示例
后端·中间件·typescript·nodejs·nest
petunsecn1 年前
Elasticsearch 的 .net 驱动NEST :Fluent API 和 Object Initializer API 的异同
elasticsearch·.net·nest·fluent api·object api
倪风62 年前
关于puppeteer项目部署到ubuntu报错记录
linux·运维·chrome·ubuntu·puppeteer·nest
皇夜_2 年前
【nest】puppeteer 使用 addScriptTag 在页面中添加方法的方式
网络爬虫·报错·puppet·nest·addscripttag
嘤嘤怪呆呆狗2 年前
【前端】Nesj 学习笔记
前端·笔记·学习·vue·nest
你的微笑、暖暖的2 年前
nestjs 全栈进阶--自定义装饰器
前端·后端·nestjs·全栈·nest
你的微笑、暖暖的2 年前
nestjs 全栈进阶--module
后端·nestjs·nest
来一颗砂糖橘2 年前
Nest安装及使用~
前端·nest·node框架