全栈手账 订阅 RSS

NestJS 笔记项目文档

一份完整的 NestJS 后端项目实战文档,包含技术选型、分层目录结构、数据库表设计与 API 接口清单、统一错误码规范,以及从启动到调用的完整流程说明与核心代码解析。

读了 13 分钟 更新于 8 月 11 日

项目简介

一个基于 NestJS 的笔记后端系统,支持用户注册登录、笔记增删改查、图片视频上传。

技术栈

技术 版本 用途
NestJS 11 后端框架
TypeORM 1.1 ORM,操作数据库
MySQL - 关系型数据库
JWT (HS256) - 登录认证
bcrypt 6 密码加密
Multer 2 文件上传
class-validator 0.15 数据验证

项目结构

文本
src/├── users/                      # 用户模块│   ├── user.entity.ts          # 用户实体│   ├── dto/│   │   └── create-user.dto.ts  # 注册 DTO│   ├── users.controller.ts     # 用户控制器│   ├── users.service.ts        # 用户服务│   └── users.module.ts         # 用户模块├── auth/                       # 认证模块│   ├── dto/│   │   └── login.dto.ts        # 登录 DTO│   ├── auth.controller.ts      # 认证控制器│   ├── auth.service.ts         # 认证服务│   ├── jwt.strategy.ts         # JWT 策略│   ├── jwt-auth.guard.ts       # JWT 守卫│   └── auth.module.ts          # 认证模块├── notes/                      # 笔记模块│   ├── note.entity.ts          # 笔记实体│   ├── dto/│   │   ├── create-note.dto.ts  # 创建笔记 DTO│   │   └── update-note.dto.ts  # 修改笔记 DTO│   ├── notes.controller.ts     # 笔记控制器│   ├── notes.service.ts        # 笔记服务│   └── notes.module.ts         # 笔记模块├── upload/                     # 上传模块│   ├── upload.config.ts        # Multer 配置│   ├── upload.controller.ts    # 上传控制器│   └── upload.module.ts        # 上传模块├── logger.middleware.ts        # 请求日志中间件├── app.module.ts               # 根模块└── main.ts                     # 入口文件

数据库设计

user 表

字段 类型 说明
id int (PK, 自增) 主键
username varchar (unique) 用户名,唯一
password varchar 密码(bcrypt 加密)
email varchar 邮箱
createTime datetime 创建时间

note 表

字段 类型 说明
id int (PK, 自增) 主键
title varchar(200) 标题
content text 文字内容
images varchar 图片 URL
videos varchar 视频 URL
userId int (FK) 外键,关联 user.id
createTime datetime 创建时间
updateTime datetime 更新时间

关系

  • user 1:N note(一个用户有多条笔记)

API 接口文档

接口地址

http://1.94.33.51:3000

一、Users 模块(无需登录)

POST /users/register — 注册用户

请求体(JSON):

json
{  "username": "zhangsan",  "password": "123456",  "email": "zhangsan@test.com"}

验证规则:

字段 规则
username 2-20 个字符
password 至少 6 个字符
email 合法邮箱格式

成功返回(201):

json
{  "username": "zhangsan",  "email": "zhangsan@test.com",  "id": 1,  "createTime": "2026-08-10T..."}

错误返回:

  • 409 — 用户名已存在
  • 400 — 数据验证不通过

二、Auth 模块(无需登录)

POST /auth/login — 登录

请求体(JSON):

json
{  "username": "zhangsan",  "password": "123456"}

成功返回(200):

json
{  "access_token": "eyJhbGciOiJIUzI1NiIs...",  "user": {    "id": 1,    "username": "zhangsan",    "email": "zhangsan@test.com"  }}

错误返回:

  • 401 — 用户名或密码错误

三、Notes 模块(需要登录)

所有接口的 Header 必须带:Authorization: Bearer <token>

1. POST /notes — 创建笔记

请求体(JSON):

json
{  "title": "我的笔记",  "content": "笔记内容",  "images": "/uploads/images/xxx.jpg",  "videos": "/uploads/videos/xxx.mp4"}

images 和 videos 可选,先上传文件拿到 URL 再填入。

成功返回(201):

json
{  "id": 1,  "title": "我的笔记",  "content": "笔记内容",  "images": "/uploads/images/xxx.jpg",  "videos": null,  "userId": 1,  "createTime": "2026-08-10T...",  "updateTime": "2026-08-10T..."}

2. GET /notes — 查询所有笔记

返回当前登录用户的所有笔记,按创建时间倒序。

成功返回(200):

json
[  {    "id": 2,    "title": "第二篇",    "content": "...",    "userId": 1,    "createTime": "...",    "updateTime": "..."  }]

3. GET /notes/:id — 查询单个笔记

路径参数: id = 笔记 ID

成功返回(200): 单个笔记对象

错误返回:

  • 404 — 笔记不存在
  • 403 — 不是自己的笔记

4. PUT /notes/:id — 修改笔记

路径参数: id = 笔记 ID

请求体(JSON,字段都可选):

json
{  "title": "修改后的标题"}

成功返回(200): 修改后的笔记对象

5. DELETE /notes/:id — 删除笔记

成功返回(200):

json
{  "message": "删除成功"}

四、Upload 模块(需要登录,form-data 格式)

Header 必须带:Authorization: Bearer <token>

1. POST /upload/image — 上传图片

Body → form-data:

Key 类型 Value
file File 选择图片文件

限制: jpg / jpeg / png / gif,最大 5MB

成功返回(201):

json
{  "message": "上传成功",  "url": "/uploads/images/1723341234-987654321.jpg",  "filename": "1723341234-987654321.jpg",  "size": 102400}

2. POST /upload/video — 上传视频

Body → form-data:

Key 类型 Value
file File 选择视频文件

限制: mp4 / avi / mov,最大 50MB

成功返回(201):

json
{  "message": "上传成功",  "url": "/uploads/videos/1723341234-987654321.mp4",  "filename": "1723341234-987654321.mp4",  "size": 5242880}

五、静态文件访问(无需登录)

GET /uploads/... — 访问上传的文件

直接在浏览器打开:

code
http://服务器IP:3000/uploads/images/文件名.jpg

错误码汇总

状态码 含义 触发场景
200 成功 GET / PUT / DELETE 成功
201 创建成功 POST 成功
400 参数错误 数据验证不通过、JSON 格式错误
401 未授权 没带 Token / Token 过期 / Token 无效
403 禁止访问 操作别人的笔记
404 不存在 笔记不存在
409 冲突 用户名已存在
500 服务器错误 代码异常

完整使用流程

文本
1. POST /users/register        → 注册账号2. POST /auth/login            → 登录,拿到 token3. POST /upload/image          → 上传图片,拿到图片 URL(可选)4. POST /upload/video          → 上传视频,拿到视频 URL(可选)5. POST /notes                 → 创建笔记,填入图片/视频 URL6. GET  /notes                 → 查看所有笔记7. GET  /notes/:id             → 查看笔记详情8. PUT  /notes/:id             → 修改笔记9. DELETE /notes/:id           → 删除笔记

核心代码说明

JWT 认证流程

文本
注册:明文密码 → bcrypt.hash(密码, 10) → 密文存数据库登录:明文密码 → bcrypt.compare(明文, 密文) → 通过 → jwtService.sign({ sub: userId }) → 返回 Token后续请求:前端带 Token → JwtAuthGuard 用 secret 验证 → 通过 → 放行

JWT Guard 实现

项目使用自定义 Guard(非 Passport),实现 CanActivate 接口:

  • 从 Authorization 头提取 Bearer Token
  • 用 JwtService.verify 验证 Token
  • 验证通过后将 { id: payload.sub, username: payload.username } 挂到 request.user
  • Controller 通过 @Request() req 获取 req.user.id

权限控制

  • 所有笔记接口都加了 @UseGuards(JwtAuthGuard)
  • Service 层每个方法都接收 userId 参数
  • 查询/修改/删除时检查 note.userId === userId,不匹配抛 403

文件上传

  • 使用 Multer diskStorage 存储到本地
  • 文件名:时间戳 + 随机数 + 原始扩展名
  • 图片存 uploads/images/,视频存 uploads/videos/
  • 通过 useStaticAssets 配置静态文件访问

开发过程中遇到的问题及解决方案

问题 原因 解决方案
pnpm install 失败 网络问题 换淘宝镜像源 registry.npmmirror.com
npm/pnpm 混用报错 lock 文件冲突 统一使用 pnpm
ERR_PNPM_IGNORED_BUILDS bcrypt 需要编译原生代码 pnpm approve-builds 批准构建
delete user.password 报错 TS 严格模式不允许 delete 非可选属性 改用解构 const { password, ...result } = user
JWT 401 未授权 Passport 策略注册问题 改用自定义 Guard 实现 CanActivate
外键约束失败 userId 为空 Guard 中 payload.sub 未映射为 id request.user = { id: payload.sub }
Express.Multer.File 类型报错 缺少类型定义包 pnpm add -D @types/multer

后续可扩展方向

  • 环境变量管理 — 使用 @nestjs/config,把数据库密码、JWT 密钥放到 .env 文件
  • 分页查询 — 笔记列表加 @Query('page') 和 @Query('limit') 分页
  • 笔记搜索 — 按标题/内容搜索,使用 QueryBuilder 或全文索引
  • 云存储 — 文件上传改为 OSS/COS 云存储,不存本地
  • Swagger 文档 — 安装 @nestjs/swagger 自动生成接口文档
  • 部署上线 — PM2 管理进程,Nginx 反向代理
  • 单元测试 — 编写 spec.ts 测试文件

前端、后端、部署、客服都是我一个人。写这里的东西都是真踩过的坑,不是抄来的教程。