# learn-nestjs **Repository Path**: gao-shunpeng/learn-nestjs ## Basic Information - **Project Name**: learn-nestjs - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2025-08-20 - **Last Updated**: 2025-10-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: Nestjs, TypeScript, MySQL, typeorm, Vue ## README # learn-nestjs(面向初学者的系统入门与实战指南) 本仓库是一个“后端 NestJS + 前端 Vue3”的学习/实践项目。本文档针对 NestJS 初学者,提供: - 概念速览:Controller/Service/Module/DI/Decorator 等核心概念 - 常用能力:守卫/拦截器/过滤器/管道/中间件 - 实战专题:JWT 认证、CASL 授权、TypeORM(迁移)、Winston 日志、统一响应/异常、请求作用域 - 前后端联调:Axios 拦截、Pinia 错误处理、Element Plus 错误提示 - 最小示例代码 + 本项目落点 + 官方文档链接 + 常见坑/排查 官方: - 网站:https://nestjs.com - 文档(中文翻译/英文权威):https://docs.nestjs.cn / https://docs.nestjs.com 目录: 1. 快速开始(后端/前端/环境变量/迁移) 2. 核心概念:Module/Controller/Provider/DI/Decorator 3. 系统能力:Guards/Interceptors/Filters/Pipes/Middleware 4. 认证与授权:Passport+JWT、CASL(含中文无权限提示) 5. 配置与环境变量:ConfigModule + 校验 6. 数据层:TypeORM 实体/Repository/迁移范式 7. 统一响应与全局异常:响应包装 + 统一错误结构 8. 日志系统:Winston + DB 持久化 + Request Scope/CLS 9. 前后端联调要点:Axios/Pinia/el-alert 10. 逐步构建一个业务模块:从 0 到上线清单 11. 常见问题与排查(401/403/作用域/连接/迁移) 12. 附录:全局提供者 APP\_\*、JWT 多来源提取、实践风格约定 — — — ## 1. 快速开始 后端(根): ``` pnpm i pnpm start:dev ``` 前端: ``` cd frontend pnpm i pnpm dev ``` 环境变量(.env.development 示例): ``` NODE_ENV=development PORT=3000 DB_TYPE=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_USERNAME=root DB_PASSWORD=your_password DB_DATABASE=learn_nest DB_SYNC=false DB_LOGGING=false SECRET=your_jwt_secret LOG_LEVELS=info ``` 迁移: ``` pnpm migration:run ``` 官方: - CLI:https://docs.nestjs.com/cli/overview - 配置:https://docs.nestjs.com/techniques/configuration — — — ## 2. 核心概念 - Module(模块) - 作用:组织控制器、服务、提供者与导入导出。 - 最小示例: ```ts @Module({ controllers: [UsersController], providers: [UsersService], exports: [UsersService], }) export class UsersModule {} ``` - 本项目:src/auth/auth.module.ts、src/logs/logs.module.ts - 文档:https://docs.nestjs.com/modules - Controller(控制器) - 作用:声明路由,处理请求/响应。 ```ts @Controller("users") export class UsersController { @Get(":id") findOne(@Param("id") id: string) { return { id }; } } ``` - 本项目:src/logs/logs.controller.ts - 文档:https://docs.nestjs.com/controllers - Provider/Service(提供者/服务) - 作用:被 DI 容器管理的可注入类(业务逻辑、仓库、工厂)。 ```ts @Injectable() export class UsersService { findOne(id: number) { /* ... */ } } ``` - 文档:https://docs.nestjs.com/providers - DI(依赖注入) - 作用:解耦构造/依赖,替代手动 new。 - 示例:构造函数注入、@InjectRepository(Entity)。 - 文档(自定义提供者/作用域):https://docs.nestjs.com/fundamentals/custom-providers - Decorator(装饰器) - 作用:声明式元数据(路由、授权、序列化等)。 - 本项目:@Controller/@Get、@UseGuards、@Can(自定义)。 - 文档(自定义装饰器):https://docs.nestjs.com/custom-decorators — — — ## 3. 系统能力 - Guards(守卫) - 位置:路由前的准入门卫,返回 true/false 或抛异常。 ```ts @Injectable() class AuthGuard implements CanActivate { canActivate(ctx: ExecutionContext) { return true; } } ``` - 本项目:JwtGuard、CaslGuard - 文档:https://docs.nestjs.com/guards - Interceptors(拦截器) - 作用:请求/响应横切逻辑(日志、缓存、统一响应)。 - 本项目:ResponseInterceptor(统一包装成功响应) - 文档:https://docs.nestjs.com/interceptors - Filters(异常过滤器) - 作用:捕获异常,统一返回结构。 - 本项目:HttpExceptionFilter(标准错误结构 + 记录日志) - 文档:https://docs.nestjs.com/exception-filters - Pipes(管道) - 作用:转换/验证(ParseIntPipe、class-validator)。 - 文档:https://docs.nestjs.com/pipes - Middleware(中间件) - 作用:更底层、在守卫前执行。 - 文档:https://docs.nestjs.com/middleware — — — ## 4. 认证与授权(Passport+JWT、CASL) - 认证(JWT) - JwtStrategy:从 Authorization: Bearer 提取 token;validate(payload) → 注入 req.user。 - JwtGuard:保护受限路由。 - 最小示例(提取器可扩展到 Cookie): ```ts super({ jwtFromRequest: ExtractJwt.fromExtractors([ ExtractJwt.fromAuthHeaderAsBearerToken(), (req: any) => req?.cookies?.access_token ?? null, ]), ignoreExpiration: false, secretOrKey: configService.get("SECRET")!, }); ``` - 文档(认证):https://docs.nestjs.com/security/authentication - 授权(CASL) - 思路:基于能力(Ability)判定是否允许执行 Action。 - 路由声明 + 守卫校验: ```ts @Can(Action.Read, 'Logs') @UseGuards(JwtGuard, CaslGuard) @Get('logs') ``` - 无权限中文提示:在 CaslGuard 校验失败处抛出 ```ts throw new ForbiddenException("您没有权限执行该操作"); ``` - CASL 官网:https://casl.js.org/ 常见坑: - 前端没带 Authorization 头 → 401 - token 过期/SECRET 不一致 → 401 - 路由未加 @UseGuards → 任何人可访问 - 能力定义缺失 → 403 — — — ## 5. 配置与环境变量(ConfigModule) - 全局化注入: ```ts ConfigModule.forRoot({ isGlobal: true }); ``` - 在策略/日志等读取配置: ```ts configService.get("SECRET"); ``` - 建议对 .env 做 joi 校验(端口/数据库/密钥)。 - 文档:https://docs.nestjs.com/techniques/configuration — — — ## 6. 数据层(TypeORM + 迁移范式) - 实体/仓库注入: ```ts @Entity() export class Logs { @PrimaryGeneratedColumn() id: number; @Column() message: string; } @InjectRepository(Logs) private repo: Repository; ``` - 迁移常用: ``` pnpm migration:generate src/migrations/xxxx pnpm migration:run pnpm migration:revert ``` - 连接配置:ormconfig.ts(基于 dotenv + ConfigEnum) - 文档: - Nest DB:https://docs.nestjs.com/techniques/database - TypeORM:https://typeorm.io — — — ## 7. 统一响应与全局异常 - 统一响应(成功): - ResponseInterceptor 将控制器返回的原始数据包装为: ```json { "code": 0, "success": true, "data": ..., "message": "ok" } ``` - 统一异常(错误): - HttpExceptionFilter 捕获异常并映射为: ```json { "code": 403, "success": false, "data": null, "message": "您没有权限执行该操作" } ``` - 建议:业务层抛标准 HttpException,交给过滤器统一格式化。 - 文档: - 过滤器:https://docs.nestjs.com/exception-filters - 拦截器:https://docs.nestjs.com/interceptors — — — ## 8. 日志系统(Winston + DB + Request Scope/CLS) - 组件: - Winston(控制台/文件输出) - LogsService(持久化 DB + 同步 Winston)— Request Scope - SimpleLoggerService(统一入口)— Request Scope - HttpExceptionFilter — Request Scope(与日志链路一致) - 为什么用 Request Scope: - 需要读取当前请求用户(req.user.userId)并落库。 - 单例无法直接注入 request-scoped 依赖 → 统一设为 Request Scope 保证上下文一致。 - 代价:每请求实例化,控制范围在“确需请求上下文”的组件上。 - 替代方案:CLS(AsyncLocalStorage) - 在 Guard/中间件写入用户到 CLS,全局单例服务可读。 - 库:https://github.com/ozkanonur/nestjs-cls - 作用域文档:https://docs.nestjs.com/fundamentals/injection-scopes - 日志文档:https://docs.nestjs.com/techniques/logger — — — ## 9. 前后端联调(Axios/Pinia/el-alert) - Axios(frontend/src/utils/http.ts): - 统一 baseURL、超时、拦截器;在请求头附带 Authorization: Bearer 。 - Pinia(frontend/src/stores): - 暴露 loading/data/error;页面 v-if="store.error" 用 el-alert 展示并 closable 清除。 - 示例(片段): ```vue ``` - 文档: - Vue3:https://vuejs.org/ - Pinia:https://pinia.vuejs.org/ - Element Plus:https://element-plus.org/ - Axios:https://axios-http.com/ — — — ## 10. 逐步构建一个模块(从 0 到上线) 1. 生成模块/控制器/服务(或手写) 2. 定义 DTO + class-validator 校验 3. 编写 Service(注入 Repository/其他服务),Controller 返回原始数据 4. 挂载 JwtGuard/CaslGuard,声明 @Can 5. 使用 SimpleLoggerService 打点(info/error/logHttpException) 6. 编写迁移并执行 migration:run 7. 前端写 API 与 Store,页面用 el-alert 接入错误 8. 自测:curl/Postman + Swagger(可选) 9. 代码格式:ESLint/Prettier;提交/PR — — — ## 11. 常见问题与排查 - 401 未认证 - 是否携带 `Authorization: Bearer `? - token 是否过期?SECRET 是否一致? - 是否仅放在 Cookie?若是,需在 JwtStrategy 增加 Cookie 提取器。 - 403 无权限 - @UseGuards(JwtGuard, CaslGuard) 是否挂上? - @Can 装饰器与 CaslAbilityService 能力定义是否覆盖该资源? - 本项目已改为中文提示。 - 过滤器/服务依赖为 undefined - 单例注入 request-scoped 依赖会失败 → 统一改为 Request Scope,或使用 CLS。 - TypeORM 连接/迁移 - .env.\* 配置是否正确?建议 migration:run 初始化,生产不要开 DB_SYNC。 — — — ## 12. 附录与实践建议 - 全局提供者: - APP_FILTER / APP_INTERCEPTOR / APP_GUARD - https://docs.nestjs.com/fundamentals/lifecycle-events#dependency-injection-scopes - JWT 多来源提取(Header + Cookie) - 见 4. 认证;可扩展 Extractors 提高容错。 - 提交/风格 - 统一用 SimpleLoggerService 打点 - 控制器返回原始数据;统一响应交给拦截器 - 异常用 HttpException,交过滤器 — — — 如需补充:Swagger 文档/接口示例、Docker 部署、ER 图、截图/演示视频、代码片段索引等,请提出,我会继续增强。 UNLICENSED(内部学习/实践)