[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"site-config":3,"footer-socials":22,"article-nestjs学习笔记":23,"comments-nestjs学习笔记":50},{"site_title":4,"site_subtitle":5,"home_intro":6,"avatar":7,"seo_keywords":8,"seo_description":9,"site_subtitle_highlight":10,"home_description":11,"about_name":12,"about_intro":13,"code_comment_2":14,"code_log":15,"code_skills":16,"code_goal":17,"code_comment_1":18,"meteor_density":19,"meteor_max_count":19,"meteor_enabled":20,"meteor_speed":21},"ShineGoldYao","架构代码，","全栈开发者 \u002F 开源爱好者 \u002F 技术探索者","https:\u002F\u002Fforuda.gitee.com\u002Favatar\u002F1762402862010015318\u002F16382196_yaoxingjin_1762402861.png!avatar200","ShiGoldYao,技术博客,全栈开发","专注于前沿技术分享与开源项目展示的个人技术博客","书写未来。","大家好，我是 ShiGoldYao。一名全栈学习与技术爱好者。在这里，我分享关于现代 Web 开发、技术框架学习记录以及极客生活的深度思考。","ShiGoldYao","我是一名全栈技术学习者，对构建高性能、可扩展的现代 Web 应用充满热情。过去一年里，我从初识互联网前后端开发，到逐步沉淀技术体系，始终保持着对前端、后端与工程化的持续探索。\n\n我坚信 “代码如诗”。除了日常学习与项目实践，我也会花大量时间关注开源社区，尝试摸索 WebAssembly、Rust 等前沿技术在浏览器端的更多可能，不断挑战性能与体验的边界。\n\n生活里的我并不只有代码：闲暇时会打打永劫无间，享受博弈与操作的快感；也喜欢打乒乓球，在运动中放松自己；当然，最幸福的时光，还是和女朋友一起慢慢生活、认真恋爱。","\u002F\u002F 🚀 开启学习之旅","","Vue , TypeScript , Nest , Mysql","成为优秀的前端全栈工程师","\u002F\u002F 欢迎来到我的技术世界","3","true","5",[],{"id":24,"title":25,"slug":26,"coverUrl":15,"summary":15,"content":27,"htmlContent":28,"categoryId":29,"viewCount":30,"likeCount":31,"isTop":32,"isPublish":31,"seoKeywords":15,"seoDescription":15,"publishTime":33,"createTime":34,"updateTime":35,"deleteTime":36,"category":37,"tags":43},"18","NestJS 学习笔记","nestjs学习笔记","# NestJS 学习笔记\n\n## 目录\n\n1. [NestJS 简介](#1-nestjs-简介)\n2. [环境搭建](#2-环境搭建)\n3. [项目结构](#3-项目结构)\n4. [控制器 Controller](#4-控制器-controller)\n5. [服务 Service（Provider）](#5-服务-serviceprovider)\n6. [模块 Module](#6-模块-module)\n7. [中间件 Middleware](#7-中间件-middleware)\n8. [异常过滤器 Exception Filter](#8-异常过滤器-exception-filter)\n9. [管道 Pipe](#9-管道-pipe)\n10. [守卫 Guard](#10-守卫-guard)\n11. [拦截器 Interceptor](#11-拦截器-interceptor)\n12. [自定义装饰器](#12-自定义装饰器)\n13. [数据库集成（TypeORM）](#13-数据库集成typeorm)\n14. [数据验证与转换（DTO）](#14-数据验证与转换dto)\n15. [身份认证（JWT）](#15-身份认证jwt)\n16. [文件上传](#16-文件上传)\n17. [Swagger 接口文档](#17-swagger-接口文档)\n18. [配置管理](#18-配置管理)\n19. [部署与优化](#19-部署与优化)\n\n***\n\n## 1. NestJS 简介\n\n### 1.1 什么是 NestJS\n\n​\tNestJS 是一个用于构建高效、可扩展的 Node.js 服务端应用程序的框架。它使用 TypeScript 构建，底层默认使用 Express（也可以切换为 Fastify），借鉴了 Angular 的架构思想（模块化、依赖注入、装饰器）。\n\n**核心特性：**\n\n- 完全支持 TypeScript\n- 模块化架构（Module）\n- 依赖注入（DI \u002F IoC）\n- 装饰器驱动开发\n- 丰富的生态系统（微服务、WebSocket、GraphQL 等）\n- 内置对测试的支持\n\n### 1.2 与 Express 的对比\n\n| 特性       | Express          | NestJS                    |\n| ---------- | ---------------- | ------------------------- |\n| 语言       | JavaScript       | TypeScript（原生支持）    |\n| 架构       | 无固定架构       | 模块化 + 依赖注入         |\n| 学习曲线   | 低               | 中等                      |\n| 适用场景   | 小型\u002F中型项目    | 中大型企业级项目          |\n| 代码组织   | 自由组织         | 强约束，分层清晰          |\n| 底层框架   | 自身             | Express \u002F Fastify         |\n| 装饰器     | 不支持           | 核心特性                  |\n| 依赖注入   | 无               | 内置 IoC 容器             |\n\n### 1.3 核心概念一览\n\nNestJS 的请求生命周期（按顺序执行）：\n\n```\n客户端请求 → 中间件(Middleware) → 守卫(Guard) → 拦截器(Interceptor-前) \n→ 管道(Pipe) → 控制器(Controller) → 服务(Service) \n→ 拦截器(Interceptor-后) → 异常过滤器(Exception Filter) → 客户端响应\n```\n\n***\n\n## 2. 环境搭建\n\n### 2.1 系统要求\n\n- Node.js >= 16.0.0\n- 包管理器：npm \u002F yarn \u002F pnpm\n- TypeScript 基础知识\n\n### 2.2 安装 NestJS CLI\n\n```bash\n# 全局安装 NestJS 脚手架\nnpm i -g @nestjs\u002Fcli\n\n# 验证安装\nnest --version\n```\n\n### 2.3 创建项目\n\n```bash\n# 创建新项目\nnest new my-nest-app\n\n# 选择包管理器 npm\u002Fyarn\u002Fpnpm\n\n# 进入项目目录\ncd my-nest-app\n\n# 启动开发服务器（热重载）\nnpm run start:dev\n```\n\n​\t启动后访问 http:\u002F\u002Flocalhost:3000，看到 `Hello World!` 即成功。\n\n### 2.4 常用 CLI 命令\n\n```bash\n# 生成模块\nnest g module users\n\n# 生成控制器\nnest g controller users\n\n# 生成服务\nnest g service users\n\n# 一键生成完整 CRUD 资源（推荐）\nnest g resource users\n\n# 生成中间件\nnest g middleware logger\n\n# 生成守卫\nnest g guard auth\n\n# 生成拦截器\nnest g interceptor transform\n\n# 生成管道\nnest g pipe validation\n\n# 生成过滤器\nnest g filter http-exception\n```\n\n***\n\n## 3. 项目结构\n\n### 3.1 目录结构说明\n\n```\nmy-nest-app\u002F\n├── dist\u002F                    # 编译输出目录\n├── node_modules\u002F\n├── src\u002F\n│   ├── app.controller.ts    # 根控制器\n│   ├── app.controller.spec.ts # 控制器测试\n│   ├── app.module.ts        # 根模块\n│   ├── app.service.ts       # 根服务\n│   └── main.ts              # 应用入口文件\n├── test\u002F                    # 端到端测试\n│   ├── app.e2e-spec.ts\n│   └── jest-e2e.json\n├── nest-cli.json            # NestJS CLI 配置\n├── tsconfig.json            # TypeScript 配置\n├── tsconfig.build.json\n└── package.json\n```\n\n### 3.2 入口文件 main.ts\n\n```typescript\n\u002F\u002F src\u002Fmain.ts\nimport { NestFactory } from '@nestjs\u002Fcore';\nimport { AppModule } from '.\u002Fapp.module';\n\nasync function bootstrap() {\n  \u002F\u002F 创建 Nest 应用实例\n  const app = await NestFactory.create(AppModule);\n  \n  \u002F\u002F 设置全局路由前缀\n  app.setGlobalPrefix('api');\n  \n  \u002F\u002F 启用 CORS 跨域\n  app.enableCors();\n  \n  \u002F\u002F 监听端口\n  await app.listen(3000);\n  console.log('服务器运行在 http:\u002F\u002Flocalhost:3000');\n}\nbootstrap();\n```\n\n### 3.3 推荐的项目结构（模块化）\n\n```\nsrc\u002F\n├── main.ts\n├── app.module.ts\n├── common\u002F                  # 公共模块\n│   ├── decorators\u002F          # 自定义装饰器\n│   ├── filters\u002F             # 异常过滤器\n│   ├── guards\u002F              # 守卫\n│   ├── interceptors\u002F        # 拦截器\n│   ├── middleware\u002F           # 中间件\n│   └── pipes\u002F               # 管道\n├── config\u002F                  # 配置模块\n│   └── config.module.ts\n├── users\u002F                   # 用户模块\n│   ├── dto\u002F                 # 数据传输对象\n│   │   ├── create-user.dto.ts\n│   │   └── update-user.dto.ts\n│   ├── entities\u002F            # 数据库实体\n│   │   └── user.entity.ts\n│   ├── users.controller.ts\n│   ├── users.service.ts\n│   ├── users.module.ts\n│   └── users.controller.spec.ts\n└── auth\u002F                    # 认证模块\n    ├── auth.controller.ts\n    ├── auth.service.ts\n    ├── auth.module.ts\n    └── strategies\u002F\n        └── jwt.strategy.ts\n```\n\n***\n\n## 4. 控制器 Controller\n\n### 4.1 控制器的作用\n\n​\t控制器负责处理传入的 HTTP 请求，返回响应给客户端。使用 `@Controller()` 装饰器标记类。\n\n### 4.2 基本用法\n\n```typescript\n\u002F\u002F src\u002Fusers\u002Fusers.controller.ts\nimport {\n  Controller,\n  Get,\n  Post,\n  Put,\n  Delete,\n  Param,\n  Body,\n  Query,\n  HttpCode,\n  HttpStatus,\n} from '@nestjs\u002Fcommon';\n\n@Controller('users') \u002F\u002F 路由前缀 \u002Fusers\nexport class UsersController {\n\n  \u002F\u002F GET \u002Fusers\n  @Get()\n  findAll() {\n    return { code: 200, msg: '查询全部用户成功', data: [] };\n  }\n\n  \u002F\u002F GET \u002Fusers\u002F:id\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return { code: 200, msg: '查询成功', data: { id } };\n  }\n\n  \u002F\u002F POST \u002Fusers\n  @Post()\n  @HttpCode(HttpStatus.CREATED) \u002F\u002F 设置状态码 201\n  create(@Body() createUserDto: any) {\n    return { code: 201, msg: '创建成功', data: createUserDto };\n  }\n\n  \u002F\u002F PUT \u002Fusers\u002F:id\n  @Put(':id')\n  update(@Param('id') id: string, @Body() updateUserDto: any) {\n    return { code: 200, msg: '修改成功', data: { id, ...updateUserDto } };\n  }\n\n  \u002F\u002F DELETE \u002Fusers\u002F:id\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return { code: 200, msg: '删除成功', data: { id } };\n  }\n}\n```\n\n### 4.3 请求参数获取\n\n```typescript\n@Controller('users')\nexport class UsersController {\n\n  \u002F\u002F Query 参数: GET \u002Fusers?page=1&limit=10\n  @Get()\n  findAll(@Query('page') page: number, @Query('limit') limit: number) {\n    return { page, limit };\n  }\n\n  \u002F\u002F 动态路由参数: GET \u002Fusers\u002F123\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return { id };\n  }\n\n  \u002F\u002F 请求体: POST \u002Fusers  body: { name: 'zhangsan', age: 20 }\n  @Post()\n  create(@Body() body: any) {\n    return body;\n  }\n\n  \u002F\u002F 获取请求头\n  @Get('info')\n  getInfo(@Headers('authorization') token: string) {\n    return { token };\n  }\n\n  \u002F\u002F 获取原始 Request 和 Response 对象\n  @Get('raw')\n  getRaw(@Req() req: Request, @Res() res: Response) {\n    res.status(200).json({ url: req.url });\n  }\n}\n```\n\n### 4.4 路由通配符与版本控制\n\n```typescript\n\u002F\u002F 通配符路由\n@Get('ab*cd')\nfindWildcard() {\n  return '匹配 abcd, ab_cd, abecd 等';\n}\n\n\u002F\u002F 路由版本控制（需在 main.ts 中启用）\n\u002F\u002F main.ts: app.enableVersioning({ type: VersioningType.URI });\n@Controller({ path: 'users', version: '1' })\nexport class UsersV1Controller {\n  @Get()\n  findAll() {\n    return 'v1 版本';\n  }\n}\n```\n\n***\n\n## 5. 服务 Service（Provider）\n\n### 5.1 服务的作用\n\n​\t服务负责处理业务逻辑，是 NestJS 中 **Provider** 的主要形式。通过 **依赖注入（DI）** 的方式注入到控制器中使用。\n\n### 5.2 创建服务\n\n```typescript\n\u002F\u002F src\u002Fusers\u002Fusers.service.ts\nimport { Injectable, NotFoundException } from '@nestjs\u002Fcommon';\n\n\u002F\u002F @Injectable() 标记这个类可以被 IoC 容器管理\n@Injectable()\nexport class UsersService {\n  \u002F\u002F 模拟数据库\n  private users = [\n    { id: 1, name: '张三', age: 20 },\n    { id: 2, name: '李四', age: 25 },\n  ];\n\n  \u002F\u002F 查询全部\n  findAll() {\n    return this.users;\n  }\n\n  \u002F\u002F 根据 ID 查询\n  findOne(id: number) {\n    const user = this.users.find((u) => u.id === id);\n    if (!user) {\n      throw new NotFoundException(`用户 ID ${id} 不存在`);\n    }\n    return user;\n  }\n\n  \u002F\u002F 新增\n  create(createUserDto: { name: string; age: number }) {\n    const newUser = {\n      id: this.users.length + 1,\n      ...createUserDto,\n    };\n    this.users.push(newUser);\n    return newUser;\n  }\n\n  \u002F\u002F 修改\n  update(id: number, updateUserDto: { name?: string; age?: number }) {\n    const user = this.findOne(id);\n    Object.assign(user, updateUserDto);\n    return user;\n  }\n\n  \u002F\u002F 删除\n  remove(id: number) {\n    const index = this.users.findIndex((u) => u.id === id);\n    if (index === -1) {\n      throw new NotFoundException(`用户 ID ${id} 不存在`);\n    }\n    return this.users.splice(index, 1)[0];\n  }\n}\n```\n\n### 5.3 在控制器中注入服务\n\n```typescript\n\u002F\u002F src\u002Fusers\u002Fusers.controller.ts\nimport { Controller, Get, Post, Put, Delete, Param, Body } from '@nestjs\u002Fcommon';\nimport { UsersService } from '.\u002Fusers.service';\n\n@Controller('users')\nexport class UsersController {\n  \u002F\u002F 构造函数注入（推荐方式）\n  constructor(private readonly usersService: UsersService) {}\n\n  @Get()\n  findAll() {\n    return {\n      code: 200,\n      msg: '查询成功',\n      data: this.usersService.findAll(),\n    };\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return {\n      code: 200,\n      msg: '查询成功',\n      data: this.usersService.findOne(+id), \u002F\u002F +id 将字符串转为数字\n    };\n  }\n\n  @Post()\n  create(@Body() createUserDto: { name: string; age: number }) {\n    return {\n      code: 201,\n      msg: '创建成功',\n      data: this.usersService.create(createUserDto),\n    };\n  }\n\n  @Put(':id')\n  update(@Param('id') id: string, @Body() updateUserDto: any) {\n    return {\n      code: 200,\n      msg: '修改成功',\n      data: this.usersService.update(+id, updateUserDto),\n    };\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return {\n      code: 200,\n      msg: '删除成功',\n      data: this.usersService.remove(+id),\n    };\n  }\n}\n```\n\n### 5.4 依赖注入原理\n\n```\n1. @Injectable() 标记 UsersService 为可注入的 Provider\n2. 在 UsersModule 的 providers 数组中注册 UsersService\n3. 控制器通过构造函数声明依赖\n4. NestJS 的 IoC 容器自动创建实例并注入\n\n好处：解耦、易测试、易替换\n```\n\n***\n\n## 6. 模块 Module\n\n### 6.1 模块的作用\n\n​\t模块是 NestJS 组织代码的基本单元。每个应用至少有一个根模块 `AppModule`，通过模块将相关的控制器和服务组织在一起。\n\n### 6.2 基本模块定义\n\n```typescript\n\u002F\u002F src\u002Fusers\u002Fusers.module.ts\nimport { Module } from '@nestjs\u002Fcommon';\nimport { UsersController } from '.\u002Fusers.controller';\nimport { UsersService } from '.\u002Fusers.service';\n\n@Module({\n  controllers: [UsersController],   \u002F\u002F 注册控制器\n  providers: [UsersService],        \u002F\u002F 注册服务（Provider）\n  exports: [UsersService],          \u002F\u002F 导出服务，供其他模块使用\n})\nexport class UsersModule {}\n```\n\n### 6.3 根模块注册\n\n```typescript\n\u002F\u002F src\u002Fapp.module.ts\nimport { Module } from '@nestjs\u002Fcommon';\nimport { UsersModule } from '.\u002Fusers\u002Fusers.module';\nimport { AuthModule } from '.\u002Fauth\u002Fauth.module';\n\n@Module({\n  imports: [UsersModule, AuthModule], \u002F\u002F 导入子模块\n  controllers: [],\n  providers: [],\n})\nexport class AppModule {}\n```\n\n### 6.4 模块分类\n\n```typescript\n\u002F\u002F 1. 功能模块 - 组织特定业务功能\n@Module({\n  controllers: [UsersController],\n  providers: [UsersService],\n})\nexport class UsersModule {}\n\n\u002F\u002F 2. 共享模块 - 被多个模块复用\n@Module({\n  providers: [HelperService],\n  exports: [HelperService], \u002F\u002F 必须导出才能被其他模块使用\n})\nexport class SharedModule {}\n\n\u002F\u002F 3. 全局模块 - 注册一次，全局可用\n@Global() \u002F\u002F 添加 @Global() 装饰器\n@Module({\n  providers: [ConfigService],\n  exports: [ConfigService],\n})\nexport class ConfigModule {}\n\n\u002F\u002F 4. 动态模块 - 可接受配置参数\n@Module({})\nexport class DatabaseModule {\n  static forRoot(options: DatabaseOptions): DynamicModule {\n    return {\n      module: DatabaseModule,\n      providers: [\n        {\n          provide: 'DATABASE_OPTIONS',\n          useValue: options,\n        },\n        DatabaseService,\n      ],\n      exports: [DatabaseService],\n    };\n  }\n}\n\u002F\u002F 使用: imports: [DatabaseModule.forRoot({ host: 'localhost', port: 3306 })]\n```\n\n***\n\n## 7. 中间件 Middleware\n\n### 7.1 中间件的作用\n\n​\t在路由处理程序之前执行的函数，可以访问请求和响应对象，常用于日志记录、身份验证前置处理等。\n\n### 7.2 创建中间件\n\n```typescript\n\u002F\u002F src\u002Fcommon\u002Fmiddleware\u002Flogger.middleware.ts\nimport { Injectable, NestMiddleware } from '@nestjs\u002Fcommon';\nimport { Request, Response, NextFunction } from 'express';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: Request, res: Response, next: NextFunction) {\n    const { method, originalUrl } = req;\n    const start = Date.now();\n\n    \u002F\u002F 响应完成时记录日志\n    res.on('finish', () => {\n      const duration = Date.now() - start;\n      console.log(`[${method}] ${originalUrl} - ${res.statusCode} ${duration}ms`);\n    });\n\n    next(); \u002F\u002F 必须调用 next()，否则请求会挂起\n  }\n}\n```\n\n### 7.3 注册中间件\n\n```typescript\n\u002F\u002F src\u002Fapp.module.ts\nimport { Module, NestModule, MiddlewareConsumer, RequestMethod } from '@nestjs\u002Fcommon';\nimport { LoggerMiddleware } from '.\u002Fcommon\u002Fmiddleware\u002Flogger.middleware';\nimport { UsersModule } from '.\u002Fusers\u002Fusers.module';\n\n@Module({\n  imports: [UsersModule],\n})\nexport class AppModule implements NestModule {\n  configure(consumer: MiddlewareConsumer) {\n    consumer\n      .apply(LoggerMiddleware)\n      \u002F\u002F 指定路由\n      .forRoutes('users');\n    \n    \u002F\u002F 也可以指定请求方法\n    \u002F\u002F .forRoutes({ path: 'users', method: RequestMethod.GET });\n    \n    \u002F\u002F 排除某些路由\n    \u002F\u002F .exclude({ path: 'users', method: RequestMethod.POST })\n    \u002F\u002F .forRoutes('users');\n  }\n}\n```\n\n### 7.4 函数式中间件（简单场景）\n\n```typescript\n\u002F\u002F 简单中间件可以用函数代替\nexport function logger(req: Request, res: Response, next: NextFunction) {\n  console.log(`[请求] ${req.method} ${req.url}`);\n  next();\n}\n\n\u002F\u002F 注册\nconsumer.apply(logger).forRoutes('*');\n```\n\n### 7.5 全局中间件\n\n```typescript\n\u002F\u002F src\u002Fmain.ts\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  \n  \u002F\u002F 全局中间件\n  app.use(logger);\n  \n  await app.listen(3000);\n}\n```\n\n***\n\n## 8. 异常过滤器 Exception Filter\n\n### 8.1 内置异常类\n\nNestJS 提供了多种内置 HTTP 异常：\n\n```typescript\nimport {\n  BadRequestException,      \u002F\u002F 400\n  UnauthorizedException,     \u002F\u002F 401\n  ForbiddenException,        \u002F\u002F 403\n  NotFoundException,         \u002F\u002F 404\n  ConflictException,         \u002F\u002F 409\n  InternalServerErrorException, \u002F\u002F 500\n} from '@nestjs\u002Fcommon';\n\n\u002F\u002F 使用方式：直接在 Service 或 Controller 中抛出\nthrow new NotFoundException('用户不存在');\nthrow new BadRequestException('参数错误');\nthrow new UnauthorizedException('请先登录');\n```\n\n### 8.2 自定义异常过滤器\n\n```typescript\n\u002F\u002F src\u002Fcommon\u002Ffilters\u002Fhttp-exception.filter.ts\nimport {\n  ExceptionFilter,\n  Catch,\n  ArgumentsHost,\n  HttpException,\n  HttpStatus,\n} from '@nestjs\u002Fcommon';\nimport { Request, Response } from 'express';\n\n@Catch(HttpException)\nexport class HttpExceptionFilter implements ExceptionFilter {\n  catch(exception: HttpException, host: ArgumentsHost) {\n    const ctx = host.switchToHttp();\n    const response = ctx.getResponse\u003CResponse>();\n    const request = ctx.getRequest\u003CRequest>();\n    const status = exception.getStatus();\n    const exceptionResponse = exception.getResponse();\n\n    \u002F\u002F 统一异常响应格式\n    response.status(status).json({\n      code: status,\n      msg: typeof exceptionResponse === 'string'\n        ? exceptionResponse\n        : (exceptionResponse as any).message,\n      data: null,\n      timestamp: new Date().toISOString(),\n      path: request.url,\n    });\n  }\n}\n```\n\n### 8.3 捕获所有异常\n\n```typescript\n\u002F\u002F src\u002Fcommon\u002Ffilters\u002Fall-exception.filter.ts\nimport {\n  ExceptionFilter,\n  Catch,\n  ArgumentsHost,\n  HttpException,\n  HttpStatus,\n} from '@nestjs\u002Fcommon';\n\n@Catch() \u002F\u002F 不传参数，捕获所有异常\nexport class AllExceptionFilter implements ExceptionFilter {\n  catch(exception: unknown, host: ArgumentsHost) {\n    const ctx = host.switchToHttp();\n    const response = ctx.getResponse();\n    const request = ctx.getRequest();\n\n    const status =\n      exception instanceof HttpException\n        ? exception.getStatus()\n        : HttpStatus.INTERNAL_SERVER_ERROR;\n\n    const message =\n      exception instanceof HttpException\n        ? exception.message\n        : '服务器内部错误';\n\n    response.status(status).json({\n      code: status,\n      msg: message,\n      data: null,\n      timestamp: new Date().toISOString(),\n      path: request.url,\n    });\n  }\n}\n```\n\n### 8.4 注册过滤器\n\n```typescript\n\u002F\u002F 方式一：全局注册（推荐）在 main.ts 中\napp.useGlobalFilters(new AllExceptionFilter());\n\n\u002F\u002F 方式二：控制器级别\n@Controller('users')\n@UseFilters(new HttpExceptionFilter())\nexport class UsersController {}\n\n\u002F\u002F 方式三：方法级别\n@Get(':id')\n@UseFilters(new HttpExceptionFilter())\nfindOne(@Param('id') id: string) {}\n```\n\n***\n\n## 9. 管道 Pipe\n\n### 9.1 管道的作用\n\n​\t管道有两个典型用途：**数据转换**（将输入数据转为目标类型）和 **数据验证**（验证输入数据是否合法）。\n\n### 9.2 内置管道\n\n```typescript\nimport {\n  ParseIntPipe,       \u002F\u002F 转换为整数\n  ParseFloatPipe,     \u002F\u002F 转换为浮点数\n  ParseBoolPipe,      \u002F\u002F 转换为布尔值\n  ParseUUIDPipe,      \u002F\u002F 验证 UUID 格式\n  ParseArrayPipe,     \u002F\u002F 转换为数组\n  DefaultValuePipe,   \u002F\u002F 设置默认值\n  ValidationPipe,     \u002F\u002F 类验证管道\n} from '@nestjs\u002Fcommon';\n\n\u002F\u002F 使用示例\n@Get(':id')\nfindOne(@Param('id', ParseIntPipe) id: number) {\n  \u002F\u002F id 已经被自动转换为 number 类型\n  \u002F\u002F 如果传入 'abc' 会自动返回 400 错误\n  return this.usersService.findOne(id);\n}\n\n@Get()\nfindAll(\n  @Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,\n  @Query('limit', new DefaultValuePipe(10), ParseIntPipe) limit: number,\n) {\n  return { page, limit };\n}\n```\n\n### 9.3 全局验证管道（最常用）\n\n```bash\n# 安装验证相关依赖\nnpm i class-validator class-transformer\n```\n\n```typescript\n\u002F\u002F src\u002Fmain.ts\nimport { ValidationPipe } from '@nestjs\u002Fcommon';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  \n  \u002F\u002F 全局启用验证管道\n  app.useGlobalPipes(\n    new ValidationPipe({\n      whitelist: true,            \u002F\u002F 自动剥离 DTO 中未定义的属性\n      forbidNonWhitelisted: true, \u002F\u002F 传入未定义属性时直接报错\n      transform: true,            \u002F\u002F 自动类型转换\n    }),\n  );\n  \n  await app.listen(3000);\n}\n```\n\n### 9.4 自定义管道\n\n```typescript\n\u002F\u002F src\u002Fcommon\u002Fpipes\u002Fparse-int.pipe.ts\nimport {\n  PipeTransform,\n  Injectable,\n  ArgumentMetadata,\n  BadRequestException,\n} from '@nestjs\u002Fcommon';\n\n@Injectable()\nexport class MyParseIntPipe implements PipeTransform\u003Cstring, number> {\n  transform(value: string, metadata: ArgumentMetadata): number {\n    const val = parseInt(value, 10);\n    if (isNaN(val)) {\n      throw new BadRequestException(`\"${value}\" 不是一个有效的数字`);\n    }\n    return val;\n  }\n}\n```\n\n***\n\n## 10. 守卫 Guard\n\n### 10.1 守卫的作用\n\n​\t守卫决定请求是否应该被路由处理程序处理，通常用于**身份认证和权限控制**。返回 `true` 放行，返回 `false` 拒绝。\n\n### 10.2 创建守卫\n\n```typescript\n\u002F\u002F src\u002Fcommon\u002Fguards\u002Fauth.guard.ts\nimport {\n  CanActivate,\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs\u002Fcommon';\nimport { Request } from 'express';\n\n@Injectable()\nexport class AuthGuard implements CanActivate {\n  canActivate(context: ExecutionContext): boolean {\n    const request = context.switchToHttp().getRequest\u003CRequest>();\n    const token = request.headers['authorization'];\n\n    if (!token) {\n      throw new UnauthorizedException('缺少认证 Token');\n    }\n\n    \u002F\u002F 验证 token 的逻辑...\n    return true;\n  }\n}\n```\n\n### 10.3 角色守卫（基于权限）\n\n```typescript\n\u002F\u002F src\u002Fcommon\u002Fguards\u002Froles.guard.ts\nimport { Injectable, CanActivate, ExecutionContext } from '@nestjs\u002Fcommon';\nimport { Reflector } from '@nestjs\u002Fcore';\n\n@Injectable()\nexport class RolesGuard implements CanActivate {\n  constructor(private reflector: Reflector) {}\n\n  canActivate(context: ExecutionContext): boolean {\n    \u002F\u002F 获取路由上通过 @Roles() 装饰器设置的角色\n    const requiredRoles = this.reflector.get\u003Cstring[]>(\n      'roles',\n      context.getHandler(),\n    );\n    if (!requiredRoles) {\n      return true; \u002F\u002F 没设置角色要求，直接放行\n    }\n\n    const request = context.switchToHttp().getRequest();\n    const user = request.user; \u002F\u002F 通常由认证中间件设置\n    return requiredRoles.some((role) => user?.roles?.includes(role));\n  }\n}\n```\n\n### 10.4 注册守卫\n\n```typescript\n\u002F\u002F 方式一：全局注册\napp.useGlobalGuards(new AuthGuard());\n\n\u002F\u002F 方式二：控制器级别\n@Controller('users')\n@UseGuards(AuthGuard)\nexport class UsersController {}\n\n\u002F\u002F 方式三：方法级别\n@Get('profile')\n@UseGuards(AuthGuard, RolesGuard)\ngetProfile() {}\n```\n\n***\n\n## 11. 拦截器 Interceptor\n\n### 11.1 拦截器的作用\n\n​\t拦截器可以在方法执行之前\u002F之后绑定额外的逻辑，常用于：统一响应格式、日志记录、缓存、超时处理等。\n\n### 11.2 统一响应格式拦截器\n\n```typescript\n\u002F\u002F src\u002Fcommon\u002Finterceptors\u002Ftransform.interceptor.ts\nimport {\n  Injectable,\n  NestInterceptor,\n  ExecutionContext,\n  CallHandler,\n} from '@nestjs\u002Fcommon';\nimport { Observable } from 'rxjs';\nimport { map } from 'rxjs\u002Foperators';\n\n\u002F\u002F 统一响应结构\ninterface Response\u003CT> {\n  code: number;\n  msg: string;\n  data: T;\n}\n\n@Injectable()\nexport class TransformInterceptor\u003CT>\n  implements NestInterceptor\u003CT, Response\u003CT>>\n{\n  intercept(\n    context: ExecutionContext,\n    next: CallHandler,\n  ): Observable\u003CResponse\u003CT>> {\n    return next.handle().pipe(\n      map((data) => ({\n        code: 200,\n        msg: '请求成功',\n        data,\n      })),\n    );\n  }\n}\n```\n\n### 11.3 日志拦截器\n\n```typescript\n\u002F\u002F src\u002Fcommon\u002Finterceptors\u002Flogging.interceptor.ts\nimport {\n  Injectable,\n  NestInterceptor,\n  ExecutionContext,\n  CallHandler,\n} from '@nestjs\u002Fcommon';\nimport { Observable } from 'rxjs';\nimport { tap } from 'rxjs\u002Foperators';\n\n@Injectable()\nexport class LoggingInterceptor implements NestInterceptor {\n  intercept(context: ExecutionContext, next: CallHandler): Observable\u003Cany> {\n    const request = context.switchToHttp().getRequest();\n    const { method, url } = request;\n    const now = Date.now();\n\n    console.log(`[请求开始] ${method} ${url}`);\n\n    return next.handle().pipe(\n      tap(() => {\n        console.log(`[请求结束] ${method} ${url} - ${Date.now() - now}ms`);\n      }),\n    );\n  }\n}\n```\n\n### 11.4 超时拦截器\n\n```typescript\n\u002F\u002F src\u002Fcommon\u002Finterceptors\u002Ftimeout.interceptor.ts\nimport {\n  Injectable,\n  NestInterceptor,\n  ExecutionContext,\n  CallHandler,\n  RequestTimeoutException,\n} from '@nestjs\u002Fcommon';\nimport { Observable, throwError, TimeoutError } from 'rxjs';\nimport { catchError, timeout } from 'rxjs\u002Foperators';\n\n@Injectable()\nexport class TimeoutInterceptor implements NestInterceptor {\n  intercept(context: ExecutionContext, next: CallHandler): Observable\u003Cany> {\n    return next.handle().pipe(\n      timeout(5000), \u002F\u002F 5秒超时\n      catchError((err) => {\n        if (err instanceof TimeoutError) {\n          return throwError(() => new RequestTimeoutException('请求超时'));\n        }\n        return throwError(() => err);\n      }),\n    );\n  }\n}\n```\n\n### 11.5 注册拦截器\n\n```typescript\n\u002F\u002F 全局注册（推荐）\napp.useGlobalInterceptors(new TransformInterceptor());\n\n\u002F\u002F 控制器级别\n@Controller('users')\n@UseInterceptors(LoggingInterceptor)\nexport class UsersController {}\n```\n\n***\n\n## 12. 自定义装饰器\n\n### 12.1 参数装饰器\n\n```typescript\n\u002F\u002F src\u002Fcommon\u002Fdecorators\u002Fcurrent-user.decorator.ts\nimport { createParamDecorator, ExecutionContext } from '@nestjs\u002Fcommon';\n\n\u002F\u002F 获取当前登录用户信息\nexport const CurrentUser = createParamDecorator(\n  (data: string, ctx: ExecutionContext) => {\n    const request = ctx.switchToHttp().getRequest();\n    const user = request.user;\n    \u002F\u002F 如果传了属性名，返回指定属性；否则返回整个 user 对象\n    return data ? user?.[data] : user;\n  },\n);\n\n\u002F\u002F 使用\n@Get('profile')\ngetProfile(@CurrentUser() user: any) {\n  return user;\n}\n\n@Get('name')\ngetName(@CurrentUser('name') name: string) {\n  return { name };\n}\n```\n\n### 12.2 方法\u002F类装饰器\n\n```typescript\n\u002F\u002F src\u002Fcommon\u002Fdecorators\u002Froles.decorator.ts\nimport { SetMetadata } from '@nestjs\u002Fcommon';\n\n\u002F\u002F 角色装饰器\nexport const Roles = (...roles: string[]) => SetMetadata('roles', roles);\n\n\u002F\u002F 使用：配合 RolesGuard\n@Post()\n@Roles('admin')\ncreate(@Body() dto: CreateUserDto) {}\n```\n\n### 12.3 组合装饰器\n\n```typescript\n\u002F\u002F 将多个装饰器组合为一个\nimport { applyDecorators, UseGuards } from '@nestjs\u002Fcommon';\n\nexport function Auth(...roles: string[]) {\n  return applyDecorators(\n    Roles(...roles),\n    UseGuards(AuthGuard, RolesGuard),\n  );\n}\n\n\u002F\u002F 使用：一个装饰器搞定认证 + 权限\n@Post()\n@Auth('admin')\ncreate(@Body() dto: CreateUserDto) {}\n```\n\n***\n\n## 13. 数据库集成（TypeORM）\n\n### 13.1 安装依赖\n\n```bash\n# TypeORM + MySQL\nnpm i @nestjs\u002Ftypeorm typeorm mysql2\n\n# 如果使用 PostgreSQL\n# npm i @nestjs\u002Ftypeorm typeorm pg\n```\n\n### 13.2 配置数据库连接\n\n```typescript\n\u002F\u002F src\u002Fapp.module.ts\nimport { Module } from '@nestjs\u002Fcommon';\nimport { TypeOrmModule } from '@nestjs\u002Ftypeorm';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'mysql',\n      host: 'localhost',\n      port: 3306,\n      username: 'root',\n      password: '123456',\n      database: 'nest_db',\n      entities: [__dirname + '\u002F**\u002F*.entity{.ts,.js}'], \u002F\u002F 自动加载实体\n      synchronize: true, \u002F\u002F 开发环境自动同步表结构（生产环境务必关闭！）\n    }),\n    UsersModule,\n  ],\n})\nexport class AppModule {}\n```\n\n### 13.3 定义实体\n\n```typescript\n\u002F\u002F src\u002Fusers\u002Fentities\u002Fuser.entity.ts\nimport {\n  Entity,\n  Column,\n  PrimaryGeneratedColumn,\n  CreateDateColumn,\n  UpdateDateColumn,\n} from 'typeorm';\n\n@Entity('users') \u002F\u002F 表名\nexport class User {\n  @PrimaryGeneratedColumn() \u002F\u002F 自增主键\n  id: number;\n\n  @Column({ length: 50, comment: '用户名' })\n  username: string;\n\n  @Column({ comment: '密码' })\n  password: string;\n\n  @Column({ nullable: true, comment: '邮箱' })\n  email: string;\n\n  @Column({ default: 1, comment: '状态 1正常 0禁用' })\n  status: number;\n\n  @Column({ type: 'enum', enum: ['admin', 'user'], default: 'user' })\n  role: string;\n\n  @CreateDateColumn({ comment: '创建时间' })\n  createTime: Date;\n\n  @UpdateDateColumn({ comment: '更新时间' })\n  updateTime: Date;\n}\n```\n\n### 13.4 在模块中注册实体\n\n```typescript\n\u002F\u002F src\u002Fusers\u002Fusers.module.ts\nimport { Module } from '@nestjs\u002Fcommon';\nimport { TypeOrmModule } from '@nestjs\u002Ftypeorm';\nimport { User } from '.\u002Fentities\u002Fuser.entity';\nimport { UsersController } from '.\u002Fusers.controller';\nimport { UsersService } from '.\u002Fusers.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])], \u002F\u002F 注册实体\n  controllers: [UsersController],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n```\n\n### 13.5 Service 中使用 Repository\n\n```typescript\n\u002F\u002F src\u002Fusers\u002Fusers.service.ts\nimport { Injectable, NotFoundException } from '@nestjs\u002Fcommon';\nimport { InjectRepository } from '@nestjs\u002Ftypeorm';\nimport { Repository, Like } from 'typeorm';\nimport { User } from '.\u002Fentities\u002Fuser.entity';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private readonly userRepository: Repository\u003CUser>,\n  ) {}\n\n  \u002F\u002F 查询全部\n  async findAll(): Promise\u003CUser[]> {\n    return await this.userRepository.find();\n  }\n\n  \u002F\u002F 分页查询\n  async findPage(page: number, limit: number) {\n    const [data, total] = await this.userRepository.findAndCount({\n      skip: (page - 1) * limit,\n      take: limit,\n      order: { createTime: 'DESC' },\n    });\n    return { data, total, page, limit };\n  }\n\n  \u002F\u002F 条件查询\n  async findByUsername(username: string): Promise\u003CUser[]> {\n    return await this.userRepository.find({\n      where: { username: Like(`%${username}%`) },\n    });\n  }\n\n  \u002F\u002F 根据 ID 查询\n  async findOne(id: number): Promise\u003CUser> {\n    const user = await this.userRepository.findOneBy({ id });\n    if (!user) {\n      throw new NotFoundException(`用户 ID ${id} 不存在`);\n    }\n    return user;\n  }\n\n  \u002F\u002F 新增\n  async create(createUserDto: Partial\u003CUser>): Promise\u003CUser> {\n    const user = this.userRepository.create(createUserDto);\n    return await this.userRepository.save(user);\n  }\n\n  \u002F\u002F 修改\n  async update(id: number, updateUserDto: Partial\u003CUser>): Promise\u003CUser> {\n    await this.userRepository.update(id, updateUserDto);\n    return this.findOne(id);\n  }\n\n  \u002F\u002F 删除\n  async remove(id: number): Promise\u003Cvoid> {\n    const result = await this.userRepository.delete(id);\n    if (result.affected === 0) {\n      throw new NotFoundException(`用户 ID ${id} 不存在`);\n    }\n  }\n}\n```\n\n### 13.6 实体关系\n\n```typescript\n\u002F\u002F 一对多关系示例\n\u002F\u002F 一个用户有多篇文章\n\n\u002F\u002F user.entity.ts\n@Entity()\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  username: string;\n\n  @OneToMany(() => Article, (article) => article.author)\n  articles: Article[];\n}\n\n\u002F\u002F article.entity.ts\n@Entity()\nexport class Article {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  @Column('text')\n  content: string;\n\n  @ManyToOne(() => User, (user) => user.articles)\n  @JoinColumn({ name: 'author_id' })\n  author: User;\n}\n\n\u002F\u002F 查询时关联加载\nconst users = await this.userRepository.find({\n  relations: ['articles'],\n});\n```\n\n***\n\n## 14. 数据验证与转换（DTO）\n\n### 14.1 什么是 DTO\n\n​\tDTO（Data Transfer Object）数据传输对象，用于定义接口接收数据的结构和验证规则。配合 `class-validator` 和 `class-transformer` 使用。\n\n### 14.2 安装依赖\n\n```bash\nnpm i class-validator class-transformer\n```\n\n### 14.3 定义 DTO\n\n```typescript\n\u002F\u002F src\u002Fusers\u002Fdto\u002Fcreate-user.dto.ts\nimport {\n  IsString,\n  IsNotEmpty,\n  IsEmail,\n  IsOptional,\n  MinLength,\n  MaxLength,\n  IsEnum,\n} from 'class-validator';\n\nexport class CreateUserDto {\n  @IsString({ message: '用户名必须是字符串' })\n  @IsNotEmpty({ message: '用户名不能为空' })\n  @MinLength(2, { message: '用户名最少2个字符' })\n  @MaxLength(20, { message: '用户名最多20个字符' })\n  username: string;\n\n  @IsString()\n  @IsNotEmpty({ message: '密码不能为空' })\n  @MinLength(6, { message: '密码最少6个字符' })\n  password: string;\n\n  @IsEmail({}, { message: '邮箱格式不正确' })\n  @IsOptional() \u002F\u002F 可选字段\n  email?: string;\n\n  @IsEnum(['admin', 'user'], { message: '角色只能是 admin 或 user' })\n  @IsOptional()\n  role?: string;\n}\n```\n\n```typescript\n\u002F\u002F src\u002Fusers\u002Fdto\u002Fupdate-user.dto.ts\nimport { PartialType } from '@nestjs\u002Fmapped-types';\nimport { CreateUserDto } from '.\u002Fcreate-user.dto';\n\n\u002F\u002F PartialType 将所有字段变为可选\nexport class UpdateUserDto extends PartialType(CreateUserDto) {}\n```\n\n### 14.4 在控制器中使用 DTO\n\n```typescript\n@Controller('users')\nexport class UsersController {\n  constructor(private readonly usersService: UsersService) {}\n\n  @Post()\n  create(@Body() createUserDto: CreateUserDto) {\n    \u002F\u002F 到达这里时，数据已经过验证\n    return this.usersService.create(createUserDto);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateUserDto: UpdateUserDto,\n  ) {\n    return this.usersService.update(id, updateUserDto);\n  }\n}\n```\n\n### 14.5 常用验证装饰器\n\n| 装饰器                | 说明           |\n| --------------------- | -------------- |\n| `@IsString()`         | 必须是字符串   |\n| `@IsNumber()`         | 必须是数字     |\n| `@IsInt()`            | 必须是整数     |\n| `@IsBoolean()`        | 必须是布尔值   |\n| `@IsEmail()`          | 必须是邮箱     |\n| `@IsNotEmpty()`       | 不能为空       |\n| `@IsOptional()`       | 可选字段       |\n| `@MinLength(n)`       | 最小长度       |\n| `@MaxLength(n)`       | 最大长度       |\n| `@Min(n)`             | 最小值         |\n| `@Max(n)`             | 最大值         |\n| `@IsEnum(entity)`     | 枚举值验证     |\n| `@IsArray()`          | 必须是数组     |\n| `@IsDate()`           | 必须是日期     |\n| `@Matches(regex)`     | 正则匹配       |\n| `@IsUrl()`            | 必须是URL      |\n| `@ValidateNested()`   | 嵌套对象验证   |\n\n***\n\n## 15. 身份认证（JWT）\n\n### 15.1 安装依赖\n\n```bash\nnpm i @nestjs\u002Fjwt @nestjs\u002Fpassport passport passport-jwt\nnpm i -D @types\u002Fpassport-jwt\n```\n\n### 15.2 Auth 模块\n\n```typescript\n\u002F\u002F src\u002Fauth\u002Fauth.module.ts\nimport { Module } from '@nestjs\u002Fcommon';\nimport { JwtModule } from '@nestjs\u002Fjwt';\nimport { PassportModule } from '@nestjs\u002Fpassport';\nimport { AuthController } from '.\u002Fauth.controller';\nimport { AuthService } from '.\u002Fauth.service';\nimport { JwtStrategy } from '.\u002Fstrategies\u002Fjwt.strategy';\nimport { UsersModule } from '..\u002Fusers\u002Fusers.module';\n\n@Module({\n  imports: [\n    UsersModule,\n    PassportModule,\n    JwtModule.register({\n      secret: 'your-secret-key', \u002F\u002F 实际项目中应放到环境变量\n      signOptions: { expiresIn: '7d' }, \u002F\u002F token 有效期 7 天\n    }),\n  ],\n  controllers: [AuthController],\n  providers: [AuthService, JwtStrategy],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n```\n\n### 15.3 Auth Service\n\n```typescript\n\u002F\u002F src\u002Fauth\u002Fauth.service.ts\nimport { Injectable, UnauthorizedException } from '@nestjs\u002Fcommon';\nimport { JwtService } from '@nestjs\u002Fjwt';\nimport { UsersService } from '..\u002Fusers\u002Fusers.service';\nimport * as bcrypt from 'bcryptjs'; \u002F\u002F npm i bcryptjs @types\u002Fbcryptjs\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private readonly usersService: UsersService,\n    private readonly jwtService: JwtService,\n  ) {}\n\n  \u002F\u002F 登录\n  async login(username: string, password: string) {\n    const user = await this.usersService.findByUsername(username);\n    if (!user) {\n      throw new UnauthorizedException('用户名或密码错误');\n    }\n\n    const isPasswordValid = await bcrypt.compare(password, user.password);\n    if (!isPasswordValid) {\n      throw new UnauthorizedException('用户名或密码错误');\n    }\n\n    \u002F\u002F 生成 JWT Token\n    const payload = { sub: user.id, username: user.username, role: user.role };\n    return {\n      access_token: this.jwtService.sign(payload),\n      user: { id: user.id, username: user.username, role: user.role },\n    };\n  }\n\n  \u002F\u002F 注册\n  async register(username: string, password: string) {\n    \u002F\u002F 密码加密\n    const hashedPassword = await bcrypt.hash(password, 10);\n    return this.usersService.create({\n      username,\n      password: hashedPassword,\n    });\n  }\n}\n```\n\n### 15.4 JWT 策略\n\n```typescript\n\u002F\u002F src\u002Fauth\u002Fstrategies\u002Fjwt.strategy.ts\nimport { Injectable, UnauthorizedException } from '@nestjs\u002Fcommon';\nimport { PassportStrategy } from '@nestjs\u002Fpassport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: 'your-secret-key',\n    });\n  }\n\n  \u002F\u002F 验证通过后，返回值会被挂载到 request.user\n  async validate(payload: any) {\n    return {\n      id: payload.sub,\n      username: payload.username,\n      role: payload.role,\n    };\n  }\n}\n```\n\n### 15.5 Auth Controller\n\n```typescript\n\u002F\u002F src\u002Fauth\u002Fauth.controller.ts\nimport { Controller, Post, Body, UseGuards, Get } from '@nestjs\u002Fcommon';\nimport { AuthGuard } from '@nestjs\u002Fpassport';\nimport { AuthService } from '.\u002Fauth.service';\nimport { CurrentUser } from '..\u002Fcommon\u002Fdecorators\u002Fcurrent-user.decorator';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(private readonly authService: AuthService) {}\n\n  @Post('login')\n  login(@Body() body: { username: string; password: string }) {\n    return this.authService.login(body.username, body.password);\n  }\n\n  @Post('register')\n  register(@Body() body: { username: string; password: string }) {\n    return this.authService.register(body.username, body.password);\n  }\n\n  \u002F\u002F 需要登录才能访问\n  @Get('profile')\n  @UseGuards(AuthGuard('jwt'))\n  getProfile(@CurrentUser() user: any) {\n    return user;\n  }\n}\n```\n\n***\n\n## 16. 文件上传\n\n### 16.1 安装依赖\n\n```bash\nnpm i @nestjs\u002Fplatform-express multer\nnpm i -D @types\u002Fmulter\n```\n\n### 16.2 文件上传接口\n\n```typescript\n\u002F\u002F src\u002Fupload\u002Fupload.controller.ts\nimport {\n  Controller,\n  Post,\n  UseInterceptors,\n  UploadedFile,\n  UploadedFiles,\n  ParseFilePipe,\n  MaxFileSizeValidator,\n  FileTypeValidator,\n} from '@nestjs\u002Fcommon';\nimport { FileInterceptor, FilesInterceptor } from '@nestjs\u002Fplatform-express';\nimport { diskStorage } from 'multer';\nimport { extname } from 'path';\n\n@Controller('upload')\nexport class UploadController {\n\n  \u002F\u002F 单文件上传\n  @Post('single')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: '.\u002Fuploads',\n        filename: (req, file, callback) => {\n          \u002F\u002F 自定义文件名：时间戳 + 随机数 + 原始扩展名\n          const uniqueName = `${Date.now()}-${Math.round(Math.random() * 1e9)}`;\n          callback(null, `${uniqueName}${extname(file.originalname)}`);\n        },\n      }),\n    }),\n  )\n  uploadSingle(\n    @UploadedFile(\n      new ParseFilePipe({\n        validators: [\n          new MaxFileSizeValidator({ maxSize: 5 * 1024 * 1024 }), \u002F\u002F 5MB\n          new FileTypeValidator({ fileType: \u002Fimage\\\u002F(png|jpeg|jpg|gif)\u002F }),\n        ],\n      }),\n    )\n    file: Express.Multer.File,\n  ) {\n    return {\n      originalname: file.originalname,\n      filename: file.filename,\n      path: file.path,\n      size: file.size,\n    };\n  }\n\n  \u002F\u002F 多文件上传\n  @Post('multiple')\n  @UseInterceptors(FilesInterceptor('files', 10)) \u002F\u002F 最多10个文件\n  uploadMultiple(@UploadedFiles() files: Express.Multer.File[]) {\n    return files.map((file) => ({\n      originalname: file.originalname,\n      filename: file.filename,\n      size: file.size,\n    }));\n  }\n}\n```\n\n### 16.3 静态文件托管\n\n```typescript\n\u002F\u002F src\u002Fmain.ts\nimport { NestFactory } from '@nestjs\u002Fcore';\nimport { NestExpressApplication } from '@nestjs\u002Fplatform-express';\nimport { join } from 'path';\n\nasync function bootstrap() {\n  const app = await NestFactory.create\u003CNestExpressApplication>(AppModule);\n  \n  \u002F\u002F 静态文件托管，访问 http:\u002F\u002Flocalhost:3000\u002Fuploads\u002Fxxx.jpg\n  app.useStaticAssets(join(__dirname, '..', 'uploads'), {\n    prefix: '\u002Fuploads',\n  });\n  \n  await app.listen(3000);\n}\n```\n\n***\n\n## 17. Swagger 接口文档\n\n### 17.1 安装依赖\n\n```bash\nnpm i @nestjs\u002Fswagger\n```\n\n### 17.2 配置 Swagger\n\n```typescript\n\u002F\u002F src\u002Fmain.ts\nimport { SwaggerModule, DocumentBuilder } from '@nestjs\u002Fswagger';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n\n  \u002F\u002F Swagger 配置\n  const config = new DocumentBuilder()\n    .setTitle('我的API文档')\n    .setDescription('NestJS 项目接口文档')\n    .setVersion('1.0')\n    .addBearerAuth() \u002F\u002F 添加 JWT 认证\n    .build();\n\n  const document = SwaggerModule.createDocument(app, config);\n  SwaggerModule.setup('api-docs', app, document); \u002F\u002F 访问 \u002Fapi-docs\n\n  await app.listen(3000);\n  console.log('Swagger 文档: http:\u002F\u002Flocalhost:3000\u002Fapi-docs');\n}\n```\n\n### 17.3 使用装饰器标注接口\n\n```typescript\nimport { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiBody } from '@nestjs\u002Fswagger';\n\n@ApiTags('用户管理') \u002F\u002F 分组标签\n@Controller('users')\nexport class UsersController {\n\n  @Get()\n  @ApiOperation({ summary: '获取所有用户', description: '返回用户列表' })\n  @ApiResponse({ status: 200, description: '查询成功' })\n  findAll() {\n    return this.usersService.findAll();\n  }\n\n  @Post()\n  @ApiBearerAuth() \u002F\u002F 标记需要 Token\n  @ApiOperation({ summary: '创建用户' })\n  @ApiBody({ type: CreateUserDto })\n  @ApiResponse({ status: 201, description: '创建成功' })\n  @ApiResponse({ status: 400, description: '参数错误' })\n  create(@Body() dto: CreateUserDto) {\n    return this.usersService.create(dto);\n  }\n}\n```\n\n### 17.4 DTO 中添加 Swagger 描述\n\n```typescript\nimport { ApiProperty, ApiPropertyOptional } from '@nestjs\u002Fswagger';\n\nexport class CreateUserDto {\n  @ApiProperty({ description: '用户名', example: 'zhangsan', minLength: 2 })\n  @IsString()\n  @IsNotEmpty()\n  username: string;\n\n  @ApiProperty({ description: '密码', example: '123456', minLength: 6 })\n  @IsString()\n  @MinLength(6)\n  password: string;\n\n  @ApiPropertyOptional({ description: '邮箱', example: 'zhangsan@example.com' })\n  @IsEmail()\n  @IsOptional()\n  email?: string;\n}\n```\n\n​\t启动后访问 http:\u002F\u002Flocalhost:3000\u002Fapi-docs 即可看到自动生成的接口文档，支持在线测试。\n\n***\n\n## 18. 配置管理\n\n### 18.1 安装依赖\n\n```bash\nnpm i @nestjs\u002Fconfig\n```\n\n### 18.2 环境变量配置\n\n```env\n# .env\nDB_HOST=localhost\nDB_PORT=3306\nDB_USERNAME=root\nDB_PASSWORD=123456\nDB_DATABASE=nest_db\nJWT_SECRET=my-jwt-secret-key\nJWT_EXPIRES_IN=7d\nPORT=3000\n```\n\n### 18.3 配置模块注册\n\n```typescript\n\u002F\u002F src\u002Fapp.module.ts\nimport { Module } from '@nestjs\u002Fcommon';\nimport { ConfigModule, ConfigService } from '@nestjs\u002Fconfig';\nimport { TypeOrmModule } from '@nestjs\u002Ftypeorm';\n\n@Module({\n  imports: [\n    \u002F\u002F 全局配置模块\n    ConfigModule.forRoot({\n      isGlobal: true,      \u002F\u002F 全局可用，无需在每个模块中导入\n      envFilePath: '.env',  \u002F\u002F 指定 .env 文件路径\n    }),\n\n    \u002F\u002F 使用 ConfigService 动态配置数据库\n    TypeOrmModule.forRootAsync({\n      imports: [ConfigModule],\n      inject: [ConfigService],\n      useFactory: (configService: ConfigService) => ({\n        type: 'mysql',\n        host: configService.get('DB_HOST'),\n        port: configService.get\u003Cnumber>('DB_PORT'),\n        username: configService.get('DB_USERNAME'),\n        password: configService.get('DB_PASSWORD'),\n        database: configService.get('DB_DATABASE'),\n        autoLoadEntities: true,\n        synchronize: true,\n      }),\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n### 18.4 在 Service 中使用配置\n\n```typescript\nimport { Injectable } from '@nestjs\u002Fcommon';\nimport { ConfigService } from '@nestjs\u002Fconfig';\n\n@Injectable()\nexport class AuthService {\n  constructor(private configService: ConfigService) {}\n\n  getJwtSecret(): string {\n    return this.configService.get\u003Cstring>('JWT_SECRET');\n  }\n}\n```\n\n***\n\n## 19. 部署与优化\n\n### 19.1 构建命令\n\n```bash\n# 开发模式（热重载）\nnpm run start:dev\n\n# 调试模式\nnpm run start:debug\n\n# 生产构建\nnpm run build\n\n# 运行生产版本\nnpm run start:prod\n```\n\n### 19.2 生产环境 main.ts 完整配置\n\n```typescript\n\u002F\u002F src\u002Fmain.ts\nimport { NestFactory } from '@nestjs\u002Fcore';\nimport { ValidationPipe } from '@nestjs\u002Fcommon';\nimport { SwaggerModule, DocumentBuilder } from '@nestjs\u002Fswagger';\nimport { AppModule } from '.\u002Fapp.module';\nimport { HttpExceptionFilter } from '.\u002Fcommon\u002Ffilters\u002Fhttp-exception.filter';\nimport { TransformInterceptor } from '.\u002Fcommon\u002Finterceptors\u002Ftransform.interceptor';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n\n  \u002F\u002F 全局路由前缀\n  app.setGlobalPrefix('api');\n\n  \u002F\u002F 跨域\n  app.enableCors();\n\n  \u002F\u002F 全局验证管道\n  app.useGlobalPipes(\n    new ValidationPipe({\n      whitelist: true,\n      forbidNonWhitelisted: true,\n      transform: true,\n    }),\n  );\n\n  \u002F\u002F 全局异常过滤器\n  app.useGlobalFilters(new HttpExceptionFilter());\n\n  \u002F\u002F 全局拦截器（统一响应格式）\n  app.useGlobalInterceptors(new TransformInterceptor());\n\n  \u002F\u002F Swagger 文档（仅开发环境）\n  if (process.env.NODE_ENV !== 'production') {\n    const config = new DocumentBuilder()\n      .setTitle('API 文档')\n      .setVersion('1.0')\n      .addBearerAuth()\n      .build();\n    const document = SwaggerModule.createDocument(app, config);\n    SwaggerModule.setup('api-docs', app, document);\n  }\n\n  const port = process.env.PORT || 3000;\n  await app.listen(port);\n  console.log(`服务器运行在 http:\u002F\u002Flocalhost:${port}`);\n}\nbootstrap();\n```\n\n### 19.3 Docker 部署\n\n```dockerfile\n# Dockerfile\nFROM node:18-alpine\n\nWORKDIR \u002Fapp\n\nCOPY package*.json .\u002F\nRUN npm ci --only=production\n\nCOPY . .\nRUN npm run build\n\nEXPOSE 3000\n\nCMD [\"node\", \"dist\u002Fmain.js\"]\n```\n\n```yaml\n# docker-compose.yml\nversion: '3.8'\nservices:\n  app:\n    build: .\n    ports:\n      - '3000:3000'\n    env_file:\n      - .env\n    depends_on:\n      - mysql\n\n  mysql:\n    image: mysql:8.0\n    environment:\n      MYSQL_ROOT_PASSWORD: 123456\n      MYSQL_DATABASE: nest_db\n    ports:\n      - '3306:3306'\n    volumes:\n      - mysql_data:\u002Fvar\u002Flib\u002Fmysql\n\nvolumes:\n  mysql_data:\n```\n\n### 19.4 PM2 部署\n\n```javascript\n\u002F\u002F ecosystem.config.js\nmodule.exports = {\n  apps: [\n    {\n      name: 'nest-app',\n      script: 'dist\u002Fmain.js',\n      instances: 'max',          \u002F\u002F 多进程\n      exec_mode: 'cluster',      \u002F\u002F 集群模式\n      env_production: {\n        NODE_ENV: 'production',\n        PORT: 3000,\n      },\n    },\n  ],\n};\n```\n\n```bash\n# 启动\npm2 start ecosystem.config.js --env production\n\n# 查看日志\npm2 logs nest-app\n\n# 重启\npm2 restart nest-app\n```\n\n***\n\n## 最佳实践总结\n\n### 项目开发流程\n\n```\n1. nest g resource xxx      → 生成 CRUD 资源\n2. 定义 Entity 实体          → 数据库表结构\n3. 定义 DTO                  → 请求参数验证\n4. 编写 Service 业务逻辑     → 操作数据库\n5. 编写 Controller           → 处理请求路由\n6. 注册到 Module             → 模块化管理\n7. 添加 Swagger 注解         → 自动生成文档\n```\n\n### 常用装饰器速查表\n\n| 装饰器               | 作用                           |\n| -------------------- | ------------------------------ |\n| `@Controller()`      | 标记控制器类                   |\n| `@Injectable()`      | 标记可注入的 Provider          |\n| `@Module()`          | 标记模块                       |\n| `@Get() @Post()` 等  | HTTP 请求方法                  |\n| `@Param()`           | 获取路由参数                   |\n| `@Query()`           | 获取查询参数                   |\n| `@Body()`            | 获取请求体                     |\n| `@Headers()`         | 获取请求头                     |\n| `@UseGuards()`       | 使用守卫                       |\n| `@UseInterceptors()` | 使用拦截器                     |\n| `@UseFilters()`      | 使用异常过滤器                 |\n| `@UsePipes()`        | 使用管道                       |\n| `@SetMetadata()`     | 设置元数据                     |\n\n***\n\n## 学习资源\n\n- [NestJS 官方文档](https:\u002F\u002Fdocs.nestjs.com)\n- [NestJS 中文文档](https:\u002F\u002Fdocs.nestjs.cn)\n- [TypeORM 文档](https:\u002F\u002Ftypeorm.io)\n- [class-validator 文档](https:\u002F\u002Fgithub.com\u002Ftypestack\u002Fclass-validator)\n- [NestJS GitHub](https:\u002F\u002Fgithub.com\u002Fnestjs\u002Fnest)\n\n***\n\n## 学习路线建议\n\n1. **入门阶段**\n   - 掌握 TypeScript 基础和装饰器语法\n   - 理解 Controller \u002F Service \u002F Module 三件套\n   - 学会使用 CLI 快速生成代码\n   - 完成简单的 CRUD 接口\n\n2. **进阶阶段**\n   - 掌握 DTO 验证与管道\n   - 学会中间件、守卫、拦截器、异常过滤器\n   - 集成 TypeORM 数据库操作\n   - 实现 JWT 身份认证\n\n3. **高级阶段**\n   - Swagger 自动文档生成\n   - 配置管理与环境变量\n   - 文件上传与静态资源\n   - 自定义装饰器与高级 DI\n\n4. **实战阶段**\n   - 完整项目开发（用户系统 + 权限管理）\n   - Docker 部署与 PM2 运维\n   - 微服务架构\n   - WebSocket 实时通信\n",null,"2",131,1,0,"2026-04-07T16:59:45.709Z","2026-04-07T16:59:45.712Z","2026-05-25T22:05:43.476Z","0",{"id":29,"categoryName":38,"slug":39,"description":40,"sort":32,"isEnable":31,"createTime":41,"updateTime":42,"deleteTime":32},"后端开发","backend-engineering","222","2026-04-03T02:36:33.016Z","2026-04-07T16:38:50.279Z",[44],{"articleId":24,"tagId":45,"createTime":34,"tag":46},"4",{"id":45,"tagName":47,"slug":47,"themeColor":48,"description":47,"createTime":49,"updateTime":49,"deleteTime":36},"Nest","#ff00c3","2026-04-07T16:39:43.674Z",[]]