# 框架-NestJS
# 简介
NestJS (opens new window) 是一个用于构建高效、可扩展的 Node.js 服务器端应用的框架。它使用渐进式 JavaScript,构建并完全支持 TypeScript(但仍然允许开发者使用纯 JavaScript 进行编码)并结合了 OOP(面向对象编程)、FP(函数式编程)和 FRP(函数式反应式编程)的元素。
相关地址
- NestJS中文网 (opens new window) 功能使用已经很详细了,可以先阅读
- 你有一份NestJS入门指南,请查收~ (opens new window) 建议先阅读
# 安装
# 安装nestjs
npm install -g @nestjs/cli
# 创建项目
nest new project-name
# 项目结构与概念
# 初始项目结构
项目安装后,会生成一个项目目录,目录结构如下:

项目中主要有src和test两个目录,src目录是项目的主要目录,test目录是测试目录。下面我们详细看看src目录的结构:
app.controller.spec.ts:控制器测试文件,用于测试控制器。app.controller.ts:控制器文件,用于处理HTTP请求。app.module.ts:模块文件,用于组织和管理模块。例如将控制器、服务、管道、过滤器等组织在一起。app.service.ts:服务文件,用于处理业务逻辑。main.ts:主文件,用于启动应用程序。
# 常见概念
module:模块,用于组织和管理模块。例如将控制器、服务、管道、过滤器等组织在一起。controller:控制器,用于处理HTTP请求。service:服务,用于处理业务逻辑。entity:实体,用于处理实体。dto:数据传输对象,用于处理数据传输。vo:视图对象,用于处理视图。exception:异常,用于处理异常。interface:接口,用于处理接口。middleware:中间件,用于处理中间件。pipe:管道是用@Injectable()装饰器注释的类,它实现了PipeTransform接口。guard:守卫是用@Injectable()装饰器注释的类,它实现了CanActivate接口。interceptor:拦截器是用@Injectable()装饰器注释的类,它实现了NestInterceptor接口。Providers: 提供器,用于处理提供器。
# 管道
在NestJS框架中,管道是一种用@Injectable()装饰器注释的类,它实现了PipeTransform接口。管道主要负责在数据到达控制器处理方法之前对其进行转换或验证。
管道的主要作用
- 数据转换:将输入数据转换为所需的形式(例如,将字符串转换为整数)
- 数据验证:验证输入数据是否满足特定条件,如果不满足则抛出异常
管道的基本实现
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
@Injectable()
export class ValidationPipe implements PipeTransform {
transform(value: any, metadata: ArgumentMetadata) {
// 在这里进行数据转换或验证
return value; // 返回转换后的值
}
}
NestJS内置管道
NestJS提供了几个内置的管道:
ValidationPipe(options?: ValidationPipeOptions):用于验证和转换请求数据ParseIntPipe(options?: ParseIntPipeOptions):将字符串参数转换为整数ParseBoolPipe(options?: ParseBoolPipeOptions):将字符串参数转换为布尔值ParseArrayPipe(options?: ParseArrayPipeOptions):将字符串参数转换为数组ParseUUIDPipe(options?: ParseUUIDPipeOptions):验证参数是否为有效的UUIDDefaultValuePipe(defaultValue: any, options?: DefaultValuePipeOptions):如果传入值为undefined,则使用默认值
管道的使用方式
- 方法级别:仅适用于特定的控制器方法
- 控制器级别:适用于控制器的所有方法
- 全局级别:适用于整个应用程序的所有控制器和方法
方法级别
// 在控制器方法中使用
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
return this.catsService.findOne(id);
}
// 在控制器类中使用
@UsePipes(new ValidationPipe()) // 使用ValidationPipe管道 验证参数
@Controller('users')
export class UsersController {
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
}
// 在全局级别使用
@Module({
imports: [
// ...
],
providers: [ValidationPipe],
})
export class AppModule {}
# 守卫
在NestJS框架中,守卫是一种用@Injectable()装饰器注释的类,它实现了CanActivate接口。守卫的主要责任是判断请求是否应该被当前路由处理程序处理,通常用于实现权限控制、认证和授权。
守卫的核心功能
- 认证:验证用户身份
- 授权:检查用户是否有权限执行特定操作
- 访问控制:基于各种条件限制对路由的访问
实际应用场景
- JWT认证守卫:验证JWT令牌的有效性
- 角色授权守卫:检查用户是否具有执行操作的角色
- API密钥守卫:验证API请求中的密钥
- 限流守卫:限制API请求频率
- IP白名单守卫:只允许特定IP地址访问
守卫的实现
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();
// 执行认证逻辑,返回true表示允许访问,false表示拒绝访问
return validateRequest(request);
}
}
守卫的使用方式
守卫可以在三个不同级别应用:
- 全局级别:适用于整个应用程序中的所有控制器和路由
- 控制器级别:适用于控制器中的所有路由
- 方法级别:仅适用于特定的路由处理程序
// 方法级别绑定示例
@Get('profile')
@UseGuards(AuthGuard)
getProfile(@Request() req) {
return req.user;
}
// 控制器级别绑定示例
@Controller('cats')
@UseGuards(RolesGuard)
export class CatsController {
// ...
}
// 全局级别绑定示例
// main.ts
const app = await NestFactory.create(AppModule);
app.useGlobalGuards(new AuthGuard());
# 实际开发下推荐的目录结构
src/
├── app.controller.ts # 控制器文件,用于处理HTTP请求。
├── app.module.ts # 模块文件,用于组织和管理模块。例如将控制器、服务、管道、过滤器等组织在一起。
├── app.service.ts # 服务文件,用于处理业务逻辑。
├── common/
│ ├── decorators/ # 装饰器文件,用于装饰控制器、服务等。
│ ├── filters/ # 过滤器文件,用于过滤HTTP请求。
│ ├── guards/ # 守卫文件,用于保护控制器、服务等。
│ ├── interceptors/ # 拦截器文件,用于拦截HTTP请求。
│ ├── pipes/ # 管道文件,用于处理HTTP请求。
│ └── utils/ # 工具文件,用于处理业务逻辑。
├── config/
│ ├── configuration.ts # 配置文件,用于配置应用程序。
│ ├── configuration.module.ts # 配置模块文件,用于组织和管理配置。
│ └── configuration.service.ts # 配置服务文件,用于处理配置。
├── modules/
│ ├── module1/ # 模块文件,用于组织和管理模块。例如将控制器、服务、管道、过滤器等组织在一起。
│ │ ├── module1.controller.ts # 控制器文件,用于处理HTTP请求。
│ │ ├── module1.module.ts # 模块文件,用于组织和管理模块。例如将控制器、服务、管道、过滤器等组织在一起。
│ │ ├── module1.service.ts # 服务文件,用于处理业务逻辑。
│ │ ├── entities/ # 实体文件,用于处理实体。
│ │ ├── └── create-module1.entity.ts # 创建模块1的实体文件。
│ │ └── dto/ # 数据传输对象文件,用于处理数据传输。
│ │ └── create-module1.dto.ts # 创建模块1的数据传输对象文件。
│ └── module2/ # 模块文件,用于组织和管理模块。例如将控制器、服务、管道、过滤器等组织在一起。
│ ├── module2.controller.ts # 控制器文件,用于处理HTTP请求。
│ ├── module2.module.ts # 模块文件,用于组织和管理模块。例如将控制器、服务、管道、过滤器等组织在一起。
│ ├── module2.service.ts # 服务文件,用于处理业务逻辑。
│ ├── entities/ # 实体文件,用于处理实体。
│ ├── └── create-module2.entity.ts # 创建模块2的实体文件。
│ └── dto/ # 数据传输对象文件,用于处理数据传输。
│ └── create-module2.dto.ts # 创建模块2的数据传输对象文件。
├── main.ts # 主文件,用于启动应用程序。
└── shared/ # 共享文件,用于处理共享的逻辑。
├── constants/ # 常量文件,用于处理常量。
├── decorators/ # 装饰器文件,用于装饰控制器、服务等。
├── dtos/ # 数据传输对象文件,用于处理数据传输。
│ ├── create-module1.vo.ts # 创建模块1的视图对象文件。
├── exceptions/ # 异常文件,用于处理异常。
├── interfaces/ # 接口文件,用于处理接口。
├── middlewares/ # 中间件文件,用于处理中间件。
├── pipes/ # 管道文件,用于处理管道。
└── services/ # 服务文件,用于处理业务逻辑。
# 常用命令
nestjs 的命令行工具(CLI)提供了许多有用的命令,以下是一些常用的命令:
nest new <project-name>:创建一个新的 NestJS 项目。nest g resource <resource-name>:生成一个新的资源。nest g controller <controller-name>:生成一个新的控制器。nest g service <service-name>:生成一个新的服务。nest g module <module-name>:生成一个新的模块。nest g pipe <pipe-name>:生成一个新的管道。nest g guard <guard-name>:生成一个新的守卫。nest g interceptor <interceptor-name>:生成一个新的拦截器。nest start:启动应用程序。nest build:构建应用程序。nest serve:启动开发服务器。nest test:运行测试。nest lint:运行 lint 检查。nest format:格式化代码。nest add <package-name>:添加一个包。nest remove <package-name>:移除一个包。nest update <package-name>:更新一个包。
# 功能
# 接入swagger
nestjs 接入 swagger 需要安装 @nestjs/swagger 和 @types/swagger-ui-express 包。
npm install @nestjs/swagger @types/swagger-ui-express
在swagger.ts文件中添加以下代码:
// swagger.ts
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { INestApplication } from '@nestjs/common';
export function setupSwagger(app: INestApplication<any>) {
const config = new DocumentBuilder()
.setTitle('NestJS API') // 设置标题
.setDescription('API description') // 设置描述
.setBasePath('api') // 设置基础路径
.setVersion('1.0') // 设置版本
// 添加JWT Bearer认证配置
.addBearerAuth(
{
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
name: 'JWT',
description: '输入JWT token',
in: 'header',
},
'JWT-auth', // 这个名称需要在控制器的@ApiBearerAuth()中使用
)
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
}
在main.ts文件中添加以下代码:
//main.ts
import { setupSwagger } from './swagger';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
setupSwagger(app); // 添加swagger
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
# 常用的Swagger装饰器
| 装饰器 | 描述 |
|---|---|
@ApiTags | 为控制器或方法添加标签 |
@ApiOperation | 为控制器方法添加操作描述 |
@ApiParam | 描述路径参数、请求参数或响应参数 |
@ApiBody | 指定请求体的DTO类型 |
@ApiResponse | 描述API的响应 |
@ApiBearerAuth | 指定请求需要携带Bearer Token |
@ApiProperty | 为DTO类型的属性添加元数据 |
@ApiQuery | 描述查询参数 |
@ApiHeader | 描述请求头信息 |
@ApiExcludeEndpoint | 标记一个控制器方法不在Swagger UI中显示 |