技术笔记,按问题排列。
记录 React、TypeScript、Node.js 与 AI Agent 的原理、取舍和工程实践。每篇文章只解决一个具体问题。
从最近更新开始,或按主题进入。
阅读最新文章最近更新
完整归档- 1. 开篇词
1. 开篇词 一直做前端开发,都会有成为全栈工程师的想法,而 Nest 就是一个很好的途径,它是 Node 最流行的企业级开发框架,提供了 IOC、AOP、微服务等架构特性。 我们会学习 Nest 全部功能,并且会顺带把 mysql、mon
- 2. 给你 5 个学习 Nest 的理由,你会心动么
2. 给你 5 个学习 Nest 的理由,你会心动么 你可能经常听到 Nest,会觉得它和我的工作也没啥关系呀,为什么要学习 Nest 呢? 这里给出 5 个学习 Nest 的理由: 最流行的 Node 企业级框架 开发 node 应用有
- 3. Nest 基础概念扫盲
3. Nest 基础概念扫盲 Nest 是对标 Java 的 Spring 框架的后端框架,它有很多概念。 对于新手来说,上来就接触这些概念可能会有点懵。 这节我们集中来过一下(这节不用实践,理解概念就好): 我们通过不同的 url 来访问
- 4. 快速掌握 Nest CLI
项目开发离不开工程化的部分,比如创建项目、编译构建、开发时 watch 文件变动自动构建等。 Nest 项目自然也是这样,所以它在 @nestjs/cli 这个包里提供了 nest 命令。 可以直接 npx 执行,npm 会把它下载下来然后
- 5. 5 种 HTTP 数据传输方式
对于前端来说,后端主要是提供 http 接口来传输数据,而这种数据传输的方式主要有 5 种: url param query form urlencoded form data json 我们分别来看一下: url param 我们可以把参
- 6. IoC 解决了什么痛点问题?
后端系统中,会有很多对象: Controller 对象:接收 http 请求,调用 Service,返回响应 Service 对象:实现业务逻辑 Repository 对象:实现对数据库的增删改查 此外,还有数据库链接对象 DataSour
- 7. 如何调试 Nest 项目
不少同学都是用 console.log 调试的,哪怕工作很多年依然是这样,这样有个致命的缺点: 你只能看到某个点的变量值,而看不到代码的整个执行路线。 对于复杂的项目来说,会用断点调试是必须的,因为这样可以看到作用域、调用栈,也就是代码的执
- 8. 使用多种 Provider,灵活注入对象
Nest 实现了 IoC 容器,会从入口模块开始扫描,分析 Module 之间的引用关系,对象之间的依赖关系,自动把 provider 注入到目标对象。 而这个 provider 也有好几种,这节我们就来看一下。 我们创建个 nest 项目
- 9. 全局模块和生命周期
模块导出 provider,另一个模块需要 imports 它才能用这些 provider。 但如果这个模块被很多模块依赖了,那每次都要 imports 就很麻烦。 能不能设置成全局的,它导出的 provider 直接可用呢? Module
- 10. AOP 架构有什么好处?
后端框架基本都是 MVC 的架构。 MVC 是 Model View Controller 的简写。MVC 架构下,请求会先发送给 Controller,由它调度 Model 层的 Service 来完成业务逻辑,然后返回对应的 View。
- 11. 一网打尽 Nest 全部装饰器
Nest 的功能都是大多通过装饰器来使用的,这节我们就把所有的装饰器过一遍。 我们创建个新的 nest 项目: nest new all decorator p npm Nest 提供了一套模块系统,通过 @Module声明模块: 通过 @
- 12. Nest 如何自定义装饰器
Nest 内置了很多装饰器,大多数功能都是通过装饰器来使用的。 但当这些装饰器都不满足需求的时候,能不能自己开发呢? 装饰器比较多的时候,能不能把多个装饰器合并成一个呢? 自然是可以的。 很多内置装饰器我们都可以自己实现。 我们来试试看:
- 13. Metadata 和 Reflector
不知道大家有没有感觉很神奇,只是通过装饰器声明了一下,然后启动 Nest 应用,这时候对象就给创建好了,依赖也给注入了。 那它是怎么实现的呢? 大家如果就这样去思考它的实现原理,还真不一定能想出来,因为缺少了一些前置知识。也就是实现 Nes
- 14. ExecutionContext:切换不同上下文
Nest 支持创建多种类型的服务: 包括 HTTP 服务、WebSocket 服务,还有基于 TCP 通信的微服务。 这三种服务都会支持 Guard、Interceptor、Exception Filter 功能。 那么问题来了: 不同类型
- 15. Module 和 Provider 的循环依赖怎么处理?
Nest 实现了一套模块系统,模块可以通过 imports 声明对其他模块的引用。 那 Module 和 Module 如果相互引用、形成循环依赖了怎么办? 这节我们就来学习下循环依赖的处理方式。 执行 创建一个 nest 项目。 然后执行
- 16. 如何创建动态模块
前面讲过,Provider 是可以通过 useFactory 动态产生的,那 Module 可不可以呢? 自然是可以的,这节我们就来学下动态模块 Dynamic Module。 我们新建一个项目: 执行 创建一个实现了 CRUD 的模块:
- 17. Nest 和 Express 的关系,如何切到 Fastify
前面我们用的 Nest 的 request、response 对象都是 Express 的,而且 Nest 也支持 Express 的中间件机制。 那 Nest 和 Express 是什么关系呢? Express 是一个处理请求、响应的库,
- 18. Nest 的 Middleware
Nest 里也有中间件 Middleware 的概念,它和 Express 的 Middleware 是一个东西么? 很像,但不一样。 上节讲过,Nest 并不是直接依赖于 Express,可以切换到别的 http 请求处理库,那 Nest
- 19. RxJS 和 Interceptor
RxJS 是一个组织异步逻辑的库,它有很多 operator,可以极大的简化异步逻辑的编写。 它是由数据源产生数据,经过一系列 operator 的处理,最后传给接收者。 这个数据源叫做 observable。 比如这样: 用 node 跑
- 20. 内置 Pipe 和自定义 Pipe
Pipe 是在参数传给 handler 之前对参数做一些验证和转换的 class, 对应的源码如下: 对每个参数都会应用 pipe: 内置的 Pipe 有这些: ValidationPipe ParseIntPipe ParseBoolPi
- 21. 如何使用 ValidationPipe 验证 Post 请求参数
上节我们学了 pipe 来对参数做验证和转换,但那些都是 get 请求的参数,如果是 post 请求呢? post 请求的数据是通过 @Body 装饰器来取,并且要有一个 dto class 来接收: (dto 是 data transfe
- 22. 如何自定义 Exception Filter
Exception Filter 是在 Nest 应用抛异常的时候,捕获它并返回一个对应的响应。 比如路由找不到时返回 404: 服务端报错时返回 500: 参数的错误返回 400: 这些都是 Exception Filter 做的事情。
- 23. 图解串一串 Nest 核心概念
前面讲了 IOC、AOP、全局模块、动态模块、自定义 provider、生命周期等概念,比较零散,这节我们画图来整体串一串。 首先,provider 是可以注入的对象,它们都有 token,比如 @Injectable 装饰器声明的 cla
- 24. 接口如何实现多版本共存
应用开发完一版上线之后,还会不断的迭代。 后续可能需要修改已有的接口,但是为了兼容,之前版本的接口还要保留。 那如何同时支持多个版本的接口呢? Nest 内置了这个功能,我们来试一下: 创建个 nest 项目。 进入项目,创建 aaa 模块
- 25. Express 如何使用 Multer 实现文件上传
Nest 的文件上传是基于 Express 的中间件 multer 实现的,所以在学习 Nest 文件上传之前,我们先学习下 multer 包的使用。 新建目录,npm init y 创建 package.json 然后安装 express
- 26. Nest 如何使用 Multer 实现文件上传
上节我们学了在 Express 里用 multer 包处理 multipart/form data 类型的请求中的 file。 单个、多个字段的单个、多个 file 都能轻松取出来。 那在 Nest 里怎么用呢? 我们新建个 nest 项目
- 27. 图书管理系统:需求分析和原型图
学到这里,我们 Nest 基础的学习就告一段落了。 我们学了 nest cli、调试、provider、动态模块、ioc、aop、middleware、interceptor、pipe、自定义装饰器等。 但是在正式做项目之前还要学习一些别的
- 28. 图书管理系统:用户模块后端开发
我们做了需求分析,并画了原型图,这节开始写下后端代码。 创建个 nest 项目: 进入项目,把服务跑起来: 浏览器访问下: 服务跑起来了。 然后我们先实现下登录、注册。 创建一个 user 模块: no spec 是不生成单测代码。 可以看
- 29. 图书管理系统:图书模块后端开发
写完用户模块的后端代码,我们继续来写图书模块。 这个模块的接口就是增删改查: 我们来添加下 book 模块: 不用生成 crud 代码了,我们自己来写就行。 该下 BookController,添加一些路由: 我们新增了 /book/lis
- 30. 图书管理系统:用户模块前端开发
后端接口写完后,我们来写前端页面。 先写登录、注册页面: 用 create vite 新建个 react 项目: 进入项目目录,把开发服务跑起来: 浏览器访问下: 然后我们添加 router: 在 main.tsx 加上路由的配置: 配置了
- 31. 图书管理系统:图书模块前端开发 图书搜索
这节继续来写图书管理模块的前端部分。 就是一个页面和几个弹窗: 我们先写下图书列表: 改下 BookManage/index.tsx 上面是一个 Form,下面是 Card 的列表。 在 index.css 写下样式: 这里还需要重置样式,
- 32. 图书管理系统:图书模块前端开发 图书增删改
这节我们来写图书新增、修改、删除、详情功能: 我们创建一个新的组件: BookManage/CreateBookModal.tsx 创建一个 Modal,包含一个 Form,有 4 个字段:name、author、description、c
- 33. 图书管理系统:项目总结
这是我们学完 Nest 基础后的第一个实战项目。 功能比较简单: 但是前后端都有,比较完整。 我们通过 json 文件实现了数据的保存,并通过动态模块,实现了在 book 和 user 模块里分别可以指定不同的文件存储路径。 基于 mult
- 34. 大文件分片上传
文件上传是常见需求,只要指定 content type 为 multipart/form data,内容就会以这种格式被传递到服务端: 服务端再按照 multipart/form data 的格式提取数据,就能拿到其中的文件。 但当文件很大
- 35. 最完美的 OSS 上传方案
文件上传是常见需求,一般我们不会把文件直接上传到应用服务器,因为单台服务器存储空间是有限的,不好扩展。 我们会用单独的 OSS (Object Storage Service)对象存储服务来上传下载文件。 比如一般会买阿里云的 OSS 服务
- 36. Nest 里如何打印日志?
前面我们都是用 console.log 打印的日志,这样有不少弊端:没有日志的不同级别的区分,不能通过开关控制是否打印等。 其实 Nest 提供了打印日志的 api,这节我们就来学习一下吧。 还是先创建个项目: 进入目录,执行 nest s
- 37. 为什么 Node 里要用 Winston 打印日志?
Node 里怎么打印日志呢? 有同学说,不也是用 console.log 么。 不,服务端打印日志一般不会用 console.log。 因为 console.log 打印完就没了,而服务端的日志经常要用来排查问题,需要搜索、分析日志内容,所
- 38. Nest 集成日志框架 Winston
我们学习了 Nest 如何自定义 logger,也学习了 Winston 的使用。 那如何在 Nest 里集成 Winston 呢? 这节我们来实现下。 创建个 nest 项目。 在 src 添加一个 MyLogger.ts 然后在 mai
- 39. 通过 Desktop 学 Docker 也太简单了
后端系统会部署很多服务,包括我们自己开发的服务,还有 mysql、redis 等中间件的服务,部署它们需要一系列依赖的安装、环境变量的设置等等。 如果你要部署多台机器的话,同样的操作要重复多次,万一哪一步漏掉了,服务就跑不起来了。 就很麻烦
- 40. 你的第一个 Dockerfile
上节我们通过 desktop 从 docker hub 拉取了 nginx 的镜像,并把它跑了起来。 跑这个镜像的时候指定了映射的端口、挂载的数据卷、环境变量等。 跑起来的容器就已经有可用的 nginx 服务了。 那如果我们要自己制作一个这
- 41. Nest 项目如何编写 Dockerfile
首先思考一个问题: dockerfile 是在哪里 build 的,在命令行工具里,还是在 docker 守护进程呢? 答案是在守护进程 docker daemon。 我没启动 docker daemon 的时候是不能 build 的,启动
- 42. 提升 Dockerfile 水平的 5 个技巧
Docker 是一种容器技术,它可以在操作系统上创建多个相互隔离的容器。容器内独立安装软件、运行服务。 但是,这个容器和宿主机还是有关联的,比如可以把宿主机的端口映射到容器内的端口、宿主机某个目录挂载到容器内的目录。 比如映射了 3000
- 43. Docker 是怎么实现的?
前面我们学习了 Docker 镜像、容器的各种操作,dockerfile 的编写,dockerignore 和镜像的多阶段构建。 是不是感觉 Docker 也没多少东西? 确实,Docker 用起来还是很简单的,学习成本不高。 那它是怎么实
- 44. 为什么 Node 应用要用 PM2 来跑?
前面我们都是 node 直接跑的 Nest 应用,但生产环境我们不会直接跑 node,而会用 pm2 来跑。 为什么要用 pm2 呢?它解决了啥问题? 想一下: 如果你的 node 应用跑的时候突然抛了个错,崩溃了,是不是需要重新跑起来?
- 45. 快速入门 MySQL
后端主要做的事情就是把数据从数据库中查出来返回给前端渲染,或者把前端提交的数据存入数据库。 学习后端技术,数据库是很重要的一步。 这节我们就来学下最流行的数据库 MySQL 的使用。 就和我们用 Docker 时一样,mysql 也是分为后
- 46. SQL 查询语句的所有语法和函数
上节我们学了 mysql 的数据库、表的创建删除,单表的增删改查。 其实增删改查的 sql 语法还有很多,这节我们就来一起过一遍。 用 docker 跑个 mysql 镜像: 上节我们跑 mysql 镜像的时候,把数据保存在了一个目录下,这
- 47. 一对一、Join 查询、级联方式
数据库中会有很多的表,分别存储不同的信息,比如学生表存学生的信息、老师表存老师的信息,班级表存班级的信息。 这些表之间不是孤立的,有着一定的关系。 比如班级和学生之间是一对多的关系,也就是一个班级可以有多个学生。 班级和老师之间是多对多的关
- 48. 一对多、多对多关系的表设计
上节我们学了一对一,这节继续来学习一对多和多对多。 一对多关系在生活中随处可见: 一个作者可以写多篇文章,而每篇文章只属于一个作者。 一个订单有多个商品,而商品只属于一个订单。 一个部门有多个员工,员工只属于一个部门。 多对多的关系也是随处
- 49. 子查询和 EXISTS
我们学习了 select 的各种语法,包括 where、limit、order by、group by、having 等,再就是 avg、count、length 等函数。 还学了多个表的 join on 关联查询。 基于这些就已经可以写出
- 50. SQL 综合练习
前面我们把 select、update、insert、delete 的语法、函数、关联查询、子查询都过了一遍,sql 学的就差不多了。 这节我们来实战下,写一些复杂的 sql。 先创建个单独的数据库: 执行它: 点击刷新,就可以看到这个 d
- 51. MySQL 的事务和隔离级别
我们学习了增删改查的 sql 语句,并进行了大量的练习。 但有个问题: 如果是两个 update 的语句,一个把订单详情表数量修改了,一个把订单表的总金额修改了。但是改订单总金额的那个 sql 执行失败了。 这时候怎么办? 数量已经改了,但
- 52. MySQL 的视图、存储过程和函数
和 mysql server 建立连接之后,可以看到它下面所有的 database。 每个 database 包含表、视图、存储过程、函数: 表的增删改查我们已经学会了。 那视图、存储过程、函数都是什么呢? 我们分别来看下: 用之前的 cu
- 53. 使用 Node 操作 MySQL 的两种方式
前面我们学习了 MySQL 的数据库、表、增删改查等,目的还是在 Node 应用里操作它。 这节我们就来学习下用 mysql2 和 typeorm 两种方式来操作 MysSQL 数据库。 先来看下 mysql2: 它是用的最多的连接 mys
- 54. 快速掌握 TypeORM
上节我们简单用了下 TypeORM,这节我们把它全部的概念过一遍。 新建一个 TypeORM 项目: 然后改下用户名密码数据库,把连接 msyql 的驱动包改为 mysql2,并修改加密密码的方式: 然后安装 mysql2: 我们分别来过一
- 55. TypeORM 一对一的映射和关联 CRUD
在数据库里,表和表之间是存在关系的。 比如用户和身份证是一对一的关系,部门和员工是一对多的关系,文章和标签是多对多的关系。 我们是通过外键来存储这种关系的,多对多的话还要建立中间表。 TypeORM 是把表、字段、表和表的关系映射成 Ent
- 56. TypeORM 一对多的映射和关联 CRUD
这节我们继续来学习 TypeORM 的一对多关系的映射和 CRUD。 我们再创建个 typeorm 项目: npx typeorm@latest init name typeorm relation mapping2 database my
- 57. TypeORM 多对多的映射和关联 CRUD
一对一我们是通过 @OneToOne 和 @JoinColumn 来把 Entity 映射成数据库表: Entity 之间的引用关系,转换为数据库表之间的外键关联的关系。 一对多我们是通过 @OneToMany 和 @ManyToOne 来
- 58. 在 Nest 里集成 TypeORM
TypeORM 怎么用我们已经学会了,在 Nest 里用那不就是再封装一层的事情么? 那怎么封装呢? 先回忆下 TypeORM 的流程: DataSource 里存放着数据库连接的配置,比如用户名、密码、驱动包、连接池配置等等。 而 Ent
- 59. TypeORM 如何保存任意层级的关系?
我们经常会见到一些多级分类的场景: 比如京东的商品分类: 新闻网站的新闻分类: 这种多层级的数据怎么存储呢? 有同学会说,很简单啊,这不就是一对多么,二级分类就用两个表,三级分类就用三个表。 这样是可以,但是都是分类,表结构是一样的,分到多
- 60. 为什么生产环境要用 TypeORM 的 Migration 迁移功能?
前面我们基于 TypeORM 操作数据库都是开启了 synchronize,只要创建或者修改了 Entity,那就会自动创建表和修改表结构。 在开发时这样很方便,只要关注代码就好了,不用管修改表结构的事情。 但是在生产环境下,用 synch
- 61. Nest 项目里如何使用 TypeORM 迁移
上节我们学了 TypeORM 的 migration。 在开发环境下,我们会开启 syncronize,自动同步 entities 到数据库表。 包括 create table 和后续的 alter table。 但是在生产环境下,我们会把
- 62. 如何动态读取不同环境的配置?
连接数据库的时候,我们指定了用户名、密码: 应用启动的时候,我们指定了端口: 而这些其实都是可以变的,在代码里写死显然不太好。 能不能抽取出来放到配置文件里呢? 自然是可以的。 node 里最常用的是 .env 格式的配置文件,它有一个专门
- 63. 快速入门 Redis
前面我们学了 mysql,它是通过表和字段来存储信息的,表和表之间通过 id 关联,叫做关系型数据库。 它提供了 sql 语言,可以通过这种语言来描述对数据的增删改查。 mysql 是通过硬盘来存储信息的,并且还要解析并执行 sql 语句,
- 64. 在 Nest 里操作 Redis
我们通过 redis cli 命令行和 RedisInsight 的 GUI 工具入门了 redis。 那在 Node 里怎么操作 redis 呢? 这就需要用 redis 的 node 的客户端了。 redis 有很多的 node 客户端
- 65. 为什么不用 Cache Manager 操作 Redis?
上节我们学了在 Nest 里操作 Redis,很多同学会问,为什么不用 cache manager 呢? 官方文档里就是用的 cache manger: 确实,cache manger 有它好用的地方,但是它的缺点更多。 为什么这么说呢?
- 66. 两种登录状态保存方式:JWT、Session
基本所有网站都有登录功能,登录之后再次请求依然是登录状态。 但 http 是无状态的,也就是说上一次请求和下一次请求之间没有任何关联。 那如何实现的这种登录状态的保存呢? 这个问题的解决有两种方案: 服务端存储的 session + coo
- 67. Nest 里实现 Session 和 JWT
上节我们知道了保存登录状态的两种方式,session + cookie、jwt,这节我们用 Nest 来实现下吧。 首先用 @nest/cli 快速创建一个 Nest.js 项目 我们先实现 session + cookie 的方式: Ne
- 68. MySQL + TypeORM + JWT 实现登录注册
学完了 mysql、typeorm、jwt/session 之后,我们来做个综合案例:登录注册。 首先,创建个新的 database: create schema 或者 create database 都可以,一个意思。 指定默认字符集 ,
- 69. 基于 ACL 实现权限控制
上节我们实现了注册和登录,有的接口只有登录可以访问,会在 Guard 里做身份验证(Authentication)。 但有的接口,不只需要登录,可能还需要一定的权限,这时就需要鉴权(Authorization)。 比如管理员登录后,可以调用
- 70. 基于 RBAC 实现权限控制
上节实现了基于 ACL 的权限控制,这节来实现 RBAC 权限控制。 RBAC 是 Role Based Access Control,基于角色的权限控制。 上节我们学的 ACL 是这样的: 直接给用户分配权限。 而 RBAC 是这样的:
- 71. 基于 Access Token 和 Refresh Token 实现登录状态无感刷新
前面我们实现了基于 JWT 的登录,流程是这样的: 登录认证通过之后,把用户信息放到 jwt 里返回: 访问接口的时候带上 jwt,在 Guard 里取出来判断是否有效,有效的话才能继续访问: 但是这样有个问题: jwt 是有有效期的,我们
- 72. 单 Token 无限续期,实现登录状态无感刷新
上节我们基于双 token 实现了登录状态的无感刷新。 这当然是能实现功能的,很多公司也这样用。 但是双 token 实现起来还是挺麻烦的。 所以实际上单 token 自动续期的方式用的也非常多。 单 token 的原理也很简单,就是登录后
- 73. 使用 Passport 做身份认证
我们实现过登录和身份认证,登录的时候基于用户名密码,后续基于 jwt。 像这种身份认证逻辑其实很通用,每个项目都会有,自然可以抽取成一个库。 先不看第三方库是怎么做的,思考下,如果让你做一个身份认证的库,你会怎么设计呢? 首先,身份认证有多
- 74. Passport 实现 GitHub 三方账号登录
我们每天都会登录各种网站,这些网站除了用户名、密码登录外,一般也都支持三方登录。 比如 google 登录、github 登录: 这样免去了输入用户名密码的麻烦,直接用别的账号来登录当前网站。 那这种三方登录是怎么实现的呢? 今天我们做一下
- 75. Passport 实现 Google 三方账号登录
上节我们实现了 Github 登录,这节继续来实现下 Google 登录。 创建个 nest 项目: 进入项目,安装 passport 的包: 然后安装 google 的策略包。 这个可以去 passport 的网站搜索: 找下载量最多的那
- 76. 为什么要使用 Docker Compose ?
我们学习了 Nest、Mysql、Redis,并且在 Nest 里远程连接 Mysql 和 Redis 来做数据存储、增删改查。 Mysql 和 Redis 都是跑在 Docker 容器里的。 部署 Nest 项目的时候也是跑的 docke
- 77. Docker 容器通信的最简单方式:桥接网络
上节我们讲 Docker Compose 的时候,涉及到多个 docker 容器的通信,我们是通过指定宿主机 ip 和端口的方式。 因为 mysql、redis 的 Docker 容器都映射到了宿主机的端口,那 nest 的容器就可以通过宿
- 78. Docker 支持重启策略,是否还需要 PM2
前面我们学习了 Docker、Docker Compose,并在 Docker 容器里通过 pm2 runtime 来跑的 node 服务。 主要是用 pm2 可以在进程崩溃的时候重启进程的功能。 而其实这个功能 Docker 也是有的。
- 79. 快速掌握 Nginx 的 2 大核心用法
Nginx 是流行的服务器,一般用它对静态资源做托管、对动态资源做反向代理。 Docker 是流行的容器技术,里面可以跑任何服务。 那 Docker + Nginx 如何结合使用呢? 我们来试一下: 搜索 nginx(这一步需要科学上网,因
- 80. 基于 Nginx 实现灰度系统
软件开发一般不会上来就是最终版本,而是会一个版本一个版本的迭代。 新版本上线前都会经过测试,但就算这样,也不能保证上线了不出问题。 所以,在公司里上线新版本代码一般都是通过灰度系统。 灰度系统可以把流量划分成多份,一份走新版本代码,一份走老
- 81. 基于 Redis 实现分布式 Session
前面我们学习了登录鉴权的两种方式 session 和 jwt。 session 是在服务端保存用户数据,然后通过 cookie 返回 sessionId。cookie 在每次请求的时候会自动带上,服务端就能根据 sessionId 找到对应
- 82. Redis + 高德地图,实现附近的充电宝
想必大家都打过车,打车软件可以根据你的当前位置搜索附近的车辆: 这两天国庆节,大家出去玩可能会借用共享充电宝。它也是基于你的位置来搜索附近充电宝: 再就是大家搜索附近的酒店、餐厅等,也是基于位置的搜索。 那么问题来了:这种附近的人、附近的酒
- 83. 用 Swagger 自动生成 Api 文档
后端开发完接口后,需要给前端一份接口文档,描述有哪些接口,是 GET 还是 POST,有哪些参数,响应是什么。 但是写完代码后再去单独写一份这样的文档还是很麻烦的,并且改动接口之后也要同步去修改接口文档。 能不能自动生成 API 接口文档呢
- 84. 如何灵活创建 DTO
Pdto 是 data transfer object,用于封装请求参数,后端应用常见对象。 当开发 CRUD 接口的时候,你会发现 create 的 dto 对象和 update 的 dto 对象很类似。 那能不能不从头创建,而是基于已有
- 85. Class Validator 的内置装饰器,如何自定义装饰器
我们会用 class validator 的装饰器对 dto 对象做校验。 那 class validator 都有哪些装饰器可用呢? 这节我们来过一遍。 创建个 CRUD 模块: 全局启用 ValidationPipe,对 dto 做校验
- 86. 序列化 Entity,你不需要 VO 对象
后端系统常见的对象有三种: Entity:数据实体,和数据库表对应。 DTO: Data Transfer Object,用于封装请求参数。 VO:Value Object,用于封装返回的响应数据。 三者的关系如下: 但文档中并没有提到 V
- 87. 手写序列化 Entity 的拦截器
上节我们学了用 class transformer + ClassSerializerInterceptor 来序列化 entity 对象,可以替代 vo。 这节我们自己来实现一下 ClassSerializerInterceptor,深入
- 88. 使用 Compodoc 生成文档
Nest 项目会有很多模块,模块之间相互依赖,模块内有 controller、service 等。 当项目复杂之后,模块之间的关系错综复杂。 这时候我们可以用 compodoc 生成一份文档,把依赖关系可视化。 compodoc 本来是给
- 89. Node 如何发邮件?
除了微信外,邮件也是我们常用的通讯方式。 那你平时都是怎么收发邮件的呢? 大多数人会回答,就用邮箱客户端啊,比如 qq 邮箱的: 但是这样体验并不好,比如写邮件的时候: 我有个漂亮的 html 页面,想直接把它作为邮件内容。 或者我想用 m
- 90. 实现基于邮箱验证码的登录
上节我们学习了用 Node 来收发邮件,其实 Node 发邮件最常见的场景还是邮箱验证码。 比如登录的时候除了可以通过用户名、密码来验证身份,还可以通过邮箱验证码来验证。 这节我们就实现下这个功能。 首先,我们写个简单的登录页面: 通过 c
- 91. 定时任务 + Redis 实现阅读量计数
文章都会有个阅读量,那这个阅读量是怎么计数的呢? 有同学说,很简单啊,这不就是文章表里加个 views 的字段,然后每次刷新页面都加一么? 这样是可以,但有两个问题: 每次刷新阅读量都加一,其实还是同一个人看的这篇文章,这样统计出来的阅读量
- 92. Nest 的 3 种定时任务
定时任务,顾名思义就是你可以设定个时间,任务会在设定的时间自动执行。 比如上节我们在 redis 里存取数据,然后通过定时任务在凌晨 4 点刷入数据库。 这节我们就更全面的学下定时任务吧。 新建个 nest 项目: 然后安装定时任务的包:
- 93. Nest 里如何实现事件通信?
后端应用中会有很多业务模块,这些业务模块之间会有互相调用的关系。 但是把一个业务模块作为依赖注入的别的业务模块也不大好。 比如下单送优惠券的活动,订单模块在订单完成后调用优惠券模块下发优惠券。 这种如果直接把优惠券模块注入到订单模块里就不大
- 94. HttpModule + Pinyin 实现天气预报查询服务
今天我们来实现一个查询城市天气预报的服务。 使用的是和风天气的免费 api。 免费的接口一天可以请求 1000 次,自己的项目足够用了: 最多可以查询未来 7 天的天气预报。 首先,登录和风天气, 然后在用户中心绑定邮箱和手机号: 之后进入
- 95. 如何记录请求日志
Nest 服务会不断处理用户用户的请求,如果我们想记录下每次请求的日志呢? 可以通过 interceptor 来做。 我们写一下: 进入项目,创建个 interceptor: 打印下日志: 这里用 nest 的 Logger 来打印日志,可
- 96. 短链服务?自己写一个
生活中我们经常遇到需要短链的场景。 比如一段很长的 url: 分享出去很不方便。 这时候就可以通过短链服务把它缩短: 点击短链会跳转到原链接: 这种在短信里很常见: 因为短信是按照字数收费的,太长不但阅读体验不好,费用也高。 所以都会生成短
- 97. Nest 实现 Server Sent Event 数据推送
提到推送数据,大家可能会首先想到 WebSocket。 确实,WebSocket 能双向通信,自然也能做服务器到浏览器的消息推送。 但如果只是单向推送消息的话,HTTP 就有这种功能,它就是 Server Sent Event。 WebSo
- 98. 用 Minio 自己搭一个 OSS 服务
文件上传是常见需求,一般我们不会直接把文件保存在服务器的某个目录下,因为服务器的存储容量是有限的,这样不好扩展。 我们会用 OSS (Object Storage Service)对象存储服务来存文件,它是支持分布式扩展的,不用担心存储容量
- 99. 前端如何直传文件到 Minio
前面我们学了 Nest 如何上传文件到服务器,但实际上基本不会直接在应用服务器存文件。 因为很容易到达存储上限,而且不好管理。 一般都会用 OSS 服务,比如阿里云的 OSS。 或者自己搭的 OSS 服务,比如用 minio。 用了 OSS
- 100. 基于 Sharp 实现 Gif 压缩工具
不知道大家有没有场景会需要 GIF 压缩,我是经常会用到。 因为公众号的图片最大支持 10M,但是我录制出来的 GIF 经常超过 10M。 比如这样一个图片: 在编辑器上传会提示超过 10 M 了: 这时候就需要 GIF 压缩,不然文章发不
- 101. 大文件如何实现流式下载?
文件上传、文件下载都是常见的需求。 大文件上传我们会通过分片上传来优化。 比如阿里云 OSS 的大文件分片上传: 那大文件下载如何优化呢? 答案也是分片下载,或者叫流式传输。 我们试一下: 创建个 Nest 项目。 在 AppControl
- 102. Puppeteer 实现爬虫,爬取 BOSS 直聘全部前端岗位
我们在找工作的时候,都会用 boss 直聘、拉钩之类的 APP 投简历。 根据职位描述筛选出适合自己的来投。 此外,职位描述也是我们简历优化的方向,甚至是平时学习的方向。 所以我觉得招聘网站的职位描述还是挺有价值的,就想把它们都爬取下来存到
- 103. 实现扫二维码登录
扫码登录是常见的功能,基本各种网站都支持。 比如掘金的登录就支持 APP 扫码的方式: 如果你 APP 没登录,扫码后会跳到登录页面: 登录之后,会进入确认界面,你可以选择授权登录或者取消: 这边确认之后,pc 网站就登录了。 知乎,b 站
- 104. Nest 的 REPL 模式
我们写过很多 Module、Service、Controller,但这些都要服务跑起来之后在浏览器里访问对应的 url,通过 get 或者 post 的方式传参来测试。 这个还是挺麻烦的,能不能像 node 的 repl 那样,直接在控制台
- 105. 实现 Excel 导入导出
Excel 是常用的办公软件,我们会用它来做数据的整理。 后台管理系统一般都会支持从 Excel 导入数据,或者导出数据到 Excel 文件: 那这种功能是如何实现的呢? 在 Node 和浏览器里,如何解析、生成 Excel 文件呢? 一般
- 106. 如何用代码动态生成 PPT
假设有一天,你需要整理一份中国所有大学信息的 ppt。 大学的信息是能搜到的,但是一份份整理到 ppt 里也太麻烦了。 能不能用代码自动生成 PPT呢? 自然是可以的。 这里大学的信息可以从中国大学 MOOC这里抓取: 我们用 puppet
- 107. 如何拿到服务器 CPU、内存、磁盘状态
在很多系统中,会有展示服务器信息的页面。 比如 CPU、内存、磁盘等: 这是怎么实现的呢? 其实通过 node 的原生 api 就可以做到。 我们还是用 Nest 写个接口来返回这些信息: 在 AppController 加个接口,用 os
- 108. Nest 如何实现国际化?
如果你的网站要支持多种语言访问,那就要做国际化。 也就是中文用户访问返回中文界面,英文用户访问返回英文界面。 如果你在外企,那可能经常要做这些,比如我在韩企的时候,要支持韩文、英文,在日企的时候,要支持日文、英文。 不只是前端要做国际化,后
- 109. 会议室预订系统:需求分析和原型图
在公司里开会,需要先预定会议室,这时候就会用到会议室预订系统。 我们第一个项目实战就来做这个系统吧。 这节来分析下需求: 首先,用户分为普通用户和管理员两种,各自有不同的功能。 普通用户可以注册,注册的时候会发邮件来验证身份,注册之后就可以
- 110. 会议室预订系统:技术方案和数据库设计
上节我们梳理了有哪些需求,并且画了原型图,明确了要做什么。 这节我们来过一下技术方案,设计下数据库,也就是怎么做。 技术栈 我们要做的是一个全栈项目,前端用 React + AntD (或者可以换成其他前端框架),后端用 Nest。 技术栈
- 111. 会议室预订系统:用户管理模块 用户注册
前两节我们理清了需求、画了原型图,并且确定了技术选型、设计了数据库,划分了接口和模块。 这节我们正式开始写代码。 首先创建个 nest 项目: 在 docker desktop 里把 mysql 的容器跑起来: 详细过程可以看 mysql
- 112. 会议室预订系统:用户管理模块 配置抽离、登录认证鉴权
上节我们实现了用户注册的功能,这节继续实现登录认证鉴权。 在那之前,我们把配置抽离一下,现在的 mysql、redis、nodemailer 等配置都直接写在代码里,不好维护。 安装 config 的包: 在 AppModule 引入下:
- 113. 会议室预订系统:用户管理模块 Interceptor、修改信息接口
用户管理模块我们实现了登录、注册、认证鉴权,还剩下一些列表、更新等接口: 这节把修改密码、修改信息的接口写完。 在那之前,我们先加一个修改响应内容的拦截器。把响应的格式改成 {code、message、data} 这种。 使用 map 操作
- 114. 会议室预订系统:用户管理模块 用户列表和分页查询
用户管理模块我们实现了注册、登录鉴权、信息修改接口,还剩下两个接口: 这节来实现下。 在那之前先考虑个问题: 成功的响应是这样的: 但是失败的响应是这样: 并不统一。 如何让响应统一成 {code、message、data} 的格式呢? 这
- 115. 会议室预订系统:用户管理模块 Swagger 接口文档
后端写完接口,都会提供一份接口文档给前端。 这节我们就来做下这件事情,通过 swagger 生成接口文档。 安装 swagger 的包: 在 main.ts 添加这段代码: 用 SwaggerModule 生成接口文档,url 是 /api
- 116. 会议室预订系统:用户管理模块 用户端登录注册页面
用户模块接口写完之后,这节我们开始写页面。 先写下用户端页面,涉及到到登录、注册、修改密码、修改个人信息这 4 个: 先新建个 react 项目: 进入项目目录,把开发服务跑起来: 浏览器访问 http://localhost:3000 可
- 117. 会议室预订系统:用户管理模块 用户端信息修改页面
用户相关的页面还剩下两个,这节我们来写一下: 首先是修改密码的页面,把注册页面的表单拿过来改改就行: css 部分如下: 跑起来是这样的: 然后再调用下后端接口。 这时我发现一个问题: 之前写的 update password 接口需要登录
- 118. 会议室预订系统:用户管理模块 头像上传
上节我们实现了用户信息的修改: 但是头像是直接填的路径,这里应该做成图片的展示,以及图片的上传。 我们需要添加个上传图片的接口: 在 UserController 里添加这个 handler: 安装用到的类型包: 在 postman 里测试
- 119. 会议室预订系统:用户管理模块 管理端用户列表页面
前面我们写了用户端的一些页面,这节继续来写管理端的。 涉及到这些页面: 这节我们来写前两个。 先新建个 react 项目: 进入项目目录,把开发服务跑起来: 浏览器访问 http://localhost:3000 可以看到这个界面: 就说明
- 120. 会议室预订系统:用户管理模块 管理端信息修改页面
这节,我们来写管理端的这两个页面: 很明显,它们是和这几个管理页面平级的,点击用户图标的时候打开: 所以,我们在它平级添加个路由: 然后创建这几个对应的组件: src/pages/ModifyMenu/ModifyMenu.stx 用到的
- 121. 会议室预订系统:会议室管理模块 后端开发
用户相关的功能,后端代码、用户端前端代码、管理端前端代码都写完了。 这节我们开始写下一个模块:会议室管理。 看下当时分析的需求: 以及我们分析出来的接口: 接口路径 请求方式 描述 /meeting room/list GET 会议室列表
- 122. 会议室预订系统:会议室管理模块 管理端前端开发
后端接口写完了,这节我们来实现下前端页面。 先写管理端的: 把管理端项目跑起来: 我们已经添加了对应的路由,但是还没做点击菜单时的切换。 加一下: 然后写下这 3 个路由的组件: src/pages/MeetingRoomManage/Me
- 123. 会议室预订系统:会议室管理模块 用户端前端开发
这节来写用户端的会议室列表: 现在,用户端首页是这样的: 需要在 / 下添加一个二级路由: 然后分别实现这三个组件: src/page/menu/Menu.tsx 引入 antd 的 Menu 实现菜单。 渲染的时候根据 useLocati
- 124. 会议室预订系统:预定管理模块 后端开发
这节我们来实现预定管理模块的后端。 涉及到这些接口: 接口路径 请求方式 描述 /booking/list GET 预订列表 /booking/approve POST 审批预订申请 /booking/add POST 申请预订 /book
- 125. 会议室预订系统:预定管理模块 管理端前端开发
这节写下预定管理模块管理端的前端部分: 对应的路由我们前面写过了: 这节来填充下内容。 首先是 table 部分: 列表接口是这样的: 根据这个指定表格列的定义,并且添加分页的处理。 其中涉及到的 User 和 Room 的类型从其他页面导
- 126. 会议室预订系统:预定管理模块 用户端前端开发
这节我们来写下预订管理模块的用户端。 把用户端代码跑起来,首先写下预订历史页面: 这个页面就是一个列表: 我们先写上面的 form: 和后台管理的页面差不多,只不过这里没有 user 的搜索。 我们登录的时候把它放到了 localStora
- 127. 会议室预订系统:统计管理模块 后端开发
写完用户模块、会议室模块、预定模块之后,就只剩下统计模块了,这节我们就来写下这个模块。 这个模块只有 2 个统计的功能: 分别是统计会议室的使用频率、用户的预定频率: 没有新的实体,只是对已有数据的统计。 在 echarts 官网可以看到柱
- 128. 会议室预订系统:统计管理模块 前端开发
上节写了统计用的两个接口,这节来加一下 swagger 文档,然后写下前端部分。 这个接口有 2 个 query 参数,返回值是一个对象,所以这样写: 涉及到的 vo 在 src/statistic/vo/UserBookignCount.
- 129. 会议室预订系统:后端项目部署到阿里云
项目写完了,本地跑没啥问题,我们最终是要把它部署到服务器上,跑起来。 我们会用到 mysql、redis、nginx,它们是这样的关系: 前端代码由 nginx 托管,处理静态请求。 并且后端服务也会经过 nginx 做反向代理,这样可以做
- 130. 会议室预订系统:前端项目部署到阿里云
上节把后端项目部署到了阿里云,可以在任意电脑上访问。 这节来部署下前端项目。 项目跑起来是这样的架构: 在之前 docker compose 的基础上加上 nginx 容器就好了。 我们进入 frontend admin 项目,加一下 ng
- 131. 会议室预定系统:用 Migration 初始化表和数据
前几节我们把项目部署到了阿里云,能够在全球各地通过 ip 来访问了。 方式是在服务器上通过 git 下载代码,然后用 docker compose 来跑。 但我们并没有把 typeorm 的 synchronize 关掉,也就是现在还是根据
- 132. 会议室预定系统:文件上传 OSS
前面我们实现了头像的上传: 图片是保存在服务器 uploads 目录下的: 然后把这个目录设置为静态文件目录: 这样图片就能直接访问了: 数据库里保存的也是这个路径: 这样是能完成功能,但有一些问题: 文件直接保存在某个目录下,服务器磁盘空
- 133. 会议室预定系统:Google 账号登录后端开发
我们的网站实现了用户名密码登录,用户忘记了密码也可以通过邮箱验证码来修改密码,之后再登录。 这样功能上没问题,但是不方便。 用户会访问很多个网站,如果每个网站都需要注册一个账号,那对于不常用的网站,很容易忘记账号密码。 解决方式就是支持三方
- 134. 会议室预定系统:Google 账号登录前端开发
上节实现了 Google 账号登录的后端代码,这节在前端代码里调用下就好了。 类似 https://login.docker.com/u/login 在登录框下加个 google 账号登录的按钮。 改下 Login.tsx 点击的时候跳转
- 135. 会议室预定系统:后端代码优化
会议室预定系统的后端功能我们实现的差不多了,但是代码层面还是有很多可以优化的地方。 这节我们集中优化下。 .env 我们在 .env 文件里保存着 redis、mysql、nodemailer、nest 服务、jwt、minio 的配置:
- 136. 会议室预定系统:集成日志框架 Winston
现在我们的日志都是直接打印在 console 的,这样开发时没问题,但是线上有时候我们要去查日志,这时候在 console 打印的日志就不是很方便。 所以我们要把日志保存在文件里,或者通过 http 发送到专门的日志服务器。 而 winst
- 137. 会议室预定系统:前端代码优化
前端代码写的比较仓促,很多代码是可以优化的。 这节我们统一来优化一下: 路由守卫 登录之后,我们会在 localStorage 保存 access token、refresh token、user info 的信息: 然后进入会议室列表页。
- 138. 会议室预定系统:全部功能测试
做完项目之后,我们整体测试一下。 按照当时的分析出的功能来测: 首先是普通用户的: 普通用户 进入 backend 和 frontend user 项目,跑起来。 注册 首先填入信息,发送验证码: 用户名要求唯一: 注册成功后我们登录下:
- 139. 会议室预定系统:项目总结
学完了 Nest 基础、MySQL、TypeORM、Docker & Docker Compose、Minio、passport 等技术之后,我们做了这个实战项目。 这个项目是会议室预定系统,分为用户端和管理端。 用户端登录之后可以查看可预
- 140. Nest 如何创建微服务?
前面我们写了很多 Http 服务了,这些服务都是单体架构的。 单体架构就是所有业务逻辑都在一个服务里实现。 这样有个问题: 项目越来越大之后,模块越来越多,代码会越来越难以维护。 并且因为代码都在一个项目里,不好扩展。比如有的业务模块想多部
- 141. Nest 的 Monorepo 和 Library
上节我们学习微服务时创建了 2 个 Nest 项目,如果微服务多了,可能会创建更多项目。 那问题来了,如果有 10 个微服务,我们就创建 10 个 Nest 项目的 git 仓库么? 那肯定不行,太难维护了。 这时候我们就需要 monore
- 142. 用 Etcd 实现微服务配置中心和注册中心
微服务架构的系统都会有配置中心和注册中心。 为什么呢? 比如说配置中心: 系统中会有很多微服务,它们会有一些配置信息,比如环境变量、数据库连接信息等。 这些配置信息散落在各个服务中,以配置文件的形式存在。 这样你修改同样的配置需要去各个服务
- 143. Nest 集成 Etcd 做注册中心、配置中心
我们学了 etcd 来做配置中心和注册中心,它比较简单,就是 key 的 put、get、del、watch 这些。 虽然简单,它却是微服务体系必不可少的组件: 服务注册、发现、配置集中管理,都是用它来做。 那 Nest 里怎么集成它呢?
- 144. 用 Nacos 实现微服务配置中心和注册中心
前面学了用 etcd 做配置中心和注册中心,这节来学习用 nacos 来做。 首先,通过 docker 把 nacos 服务跑起来: 搜索 nacos/nacos server 的镜像: 填一下启动参数: 指定环境变量 MODE 为 sta
- 145. 基于 GRPC 实现跨语言的微服务通信
后端系统大多都是微服务的架构,而且还可能同时有多种语言实现的微服务,比如 java、go、python、c++、node 等。 那么问题来了,多种语言实现的微服务之间如何通信呢? 有的同学会说 http 不就行? 但 http 是文本传输,
- 146. 快速入门 ORM 框架 Prisma
我们学习了 TypeORM,它是一个传统的 ORM 框架,也就是把表映射到 entity 类,把表的关联映射成 entity 类的属性关联。 完成 entity 和表的映射之后,你只要调用 userRepository 和 postRepo
- 147. Prisma 的全部命令
上节我们入门了 prisma,定义了 model 和表的映射,并且做了 CRUD。 这节来过一遍 Prisma 的全部命令。 有这些: init:创建 schema 文件 generate: 根据 shcema 文件生成 client 代码
- 148. Prisma 的全部 Schema 语法
这节我们来学习下 Prisma 的 schema 文件的全部语法。 先创建个新项目: 全局安装 prisma: 然后进入项目,执行 init 命令: 生成了 .env 和 schema 文件: 然后改下 .env 文件的数据库连接信息: 改
- 149. Primsa Client 单表 CRUD 的全部 Api
我们学了 Prisma 的命令、schema 的语法,这节来过一遍 Prisma Client 的 api。 这节只涉及单个表的 CRUD 的 api。 创建个新项目: 进入项目,执行 init 命令: 生成了 .env 和 schema
- 150. Prisma Client 多表 CRUD 的全部 Api
上节我们过了一遍 Prisma Client 做 CRUD 的 api,但那只是针对单表的,这节我们把涉及到多表的 CRUD 的 api 过一遍。 创建个新项目: 进入项目,执行 init 命令: 生成了 .env 和 schema 文件:
- 151. 在 Nest 里集成 Prisma
我们学 Prisma,最终还是要和 Nest 结合用的,就像我们学 TypeORM 时那样。 其实也很简单,还是基于 schema 生成 client 的 api,然后调用这些 api 来 CRUD。 只不过 Nest 里的调用方式不大一样
- 152. 为什么前端监控系统要用 RabbitMQ?
前端监控系统是采集用户端的异常、性能、业务埋点等数据上报,在服务端做存储,并支持可视化分析的平台。 用户量可能很大,采集的数据可能比较多,这时候服务端的并发压力会比较大,要是直接存入数据库,那数据库服务很可能会崩掉。 那就用现在的数据库,如
- 153. 基于 Redis 实现关注关系
在掘金、知乎、抖音等平台,我们可以关注其他用户,其他用户也可以关注我们,而且如果彼此关注,会标出共同关注: 这种关注、被关注,相互关注,我们每天都能见到。 那它是怎么实现的呢? 一般是用 redis 的 Set 实现的。 Set 是集合,有
- 154. 基于 Redis 实现各种排行榜(周榜、月榜、年榜)
生活中各种排行榜可太多了。 比如经常有瓜的微博文娱榜: 掘金的文章榜: 作者榜: 微信的步数排行榜: 我最近订的自习室也有学习时长排行榜: 排行的依据各有不同,有的是根据学习时长,有的是根据阅读数、点赞数,有的是根据搜索次数等。 那这些排行
- 155. 考试系统:需求分析
这节开始,我们来做微服务的实战项目:考试系统。 大概有这些功能: 用户可以注册、登录、修改密码。 登录后可以查看考试列表,可以创建新的考试,也可以删除考试。 删除的考试会放到回收站。 试卷的编辑器是一个类似低代码的拖拽编辑的形式,有多种题型
- 156. 考试系统:技术方案和数据库设计
分析完需求,这节来设计下技术方案。 技术栈 前端部分 React + Antd Design,脚手架用 create vite: 后端服务是 Nest + Prisma,会拆分多个微服务,之间用 TCP 通信。 数据库是 mysql + r
- 157. 考试系统:微服务、Lib 拆分
这节我们来做下微服务的拆分,并把一些公共 Module 放到 Lib 里。 创建项目: 然后添加 4 个 app: 看下现在的目录: 还有 nest cli.json 我们改下 user、exam、answer、analyse 的服务的启动
- 158. 考试系统;用户注册
这节正式进入开发,我们先来开发注册功能。 在 docker desktop 里把 mysql 的容器跑起来: 安装 prisma 然后执行 prisma init 创建 schema 文件: 改下 .env 的配置: 并且修改下 schem
- 159. 考试系统:用户登录、修改密码
这节我们实现下登录、修改密码。 在 UserController 添加一个 login 的路由: 创建 src/dto/login user.dto.ts: 测试下: 服务端打印了接收的参数。 ValidationPipe 开启 trans
- 160. 考试系统:考试微服务
这节我们来实现考试微服务的功能。 首先创建考试表: 字段名 数据类型 描述 id INT 考试ID createUserId INT 创建者ID name VARCHAR(50) 考试名 isPublish BOOLEAN 是否发布 isD
- 161. 考试系统:登录、注册页面
先不着急写其他两个微服务,我们先来写一下前端页面。 先来写下用户注册、登录页面。 新建个 react 项目: 进入项目目录,把开发服务跑起来: 浏览器访问 http://localhost:5173 可以看到这个界面: 就说明 react
- 162. 考试系统:修改密码、试卷列表页面
这节继续来写修改密码页面,还有试卷列表页面: 首先是修改密码的页面 src/pages/UpdatePassword: css 部分如下: 跑起来是这样的: 然后再调用下后端接口。 在 interfaces 添加这两个接口: 更改密码页面里
- 163. 考试系统:新增试卷、回收站
这节我们实现新增试卷和回收站的功能。 先在 interfaces/index.tsx 加一下 add 接口: 然后写一下新增试卷的弹窗: pages/ExamList/ExamAddModal.tsx Modal 内是一个表单,点击创建会调
- 164. 考试系统:试卷编辑器
这节我们来写下试卷编辑器。 和问卷星的类似: 可以选择不同的题型,然后设置题目的内容,答案、分值、答案解析等。 我们先来设计下 json 的数据结构: 这只是一个列表的 json,比较简单。 大概是这样的结构: type 是题型 optio
- 165. 考试系统:试卷回显、预览、保存
上节我们实现了试卷编辑器: 但没有和对应 id 的试卷关联。 这节来做下回显和关联。 回显就是根据 id 查询对应的试卷内容。 我们之前没开发这个接口,加一下: 在 ExamService 加一下实现: 试一下: 在 interfaces/
- 166. 考试系统:答卷微服务
这节回过头来继续写答卷微服务。 首先创建答卷表: 字段名 数据类型 描述 id INT 答卷ID answererId INT 答题人ID examId INT 答卷ID content TEXT 答卷JSON score INT 分数 c
- 167. 考试系统:答题页面
写完了答卷的后端部分,这节来写下前端页面。 在问卷星里,编辑完试卷后,点击发布后,会生成链接和二维码: 打开链接就可以答题了: 答完点提交会立刻判卷,给出分数,还可以查看正确答案和解析: 这节我们来实现这部分功能。 首先给编辑按钮加上跳转编
- 168. 考试系统:自动判卷
上节实现了答卷的提交,但是提交之后的分数页面还没写: 这节来写一下。 我们现在并没有做分数的计算: 答卷表里的 score 都是 0 那怎么实现分数的计算呢? 也很简单,每个试卷的内容保存在 exam 表里,并且都保存了正确答案。 我们只要
- 169. 考试系统:分析微服务、排行榜页面
这节来写下分析的微服务。 主要是排行榜的接口: 接口路径 请求方式 描述 /analyse/ranking GET 成绩排行榜 只要涉及到排行榜,一般都是用 redis 的 zset (有序集合)来做。 而且 zset 可以用 zuion
- 170. 考试系统:整体测试
项目做完后我们整体测试下。 首先注册一个账号: 填入邮箱后点击发送验证码。 输入验证码后点击注册。 然后用这个账号登录下: 登录成功进入试卷列表页面。 如果忘了密码可以重置: 试卷列表可以创建试卷: 删除试卷会放入回收站: 我们编辑下试卷:
- 171. 考试系统:项目总结
学完了微服务和 monorepo 后,我们做了这个考试系统项目。 整体是模仿问卷星的流程,从创建考试、考试编辑器、答卷、自动判分、到排行榜等,流程比较完整。 我们通过 monorepo 的方式组织项目: 4 个微服务都是 apps 下的单独
- 172. 用 Node.Js 手写 WebSocket 协议
实时的双向数据通信,我们一般会用 WebSocket 来做。 HTTP 的协议格式我们很清楚,就是 header、body 这些。 那 WebSocket 的协议格式是什么样的呢? 这节我们就用 Node 来实现下 WebSocket 协议
- 173. Nest 开发 WebSocket 服务
我们最常用的网络协议是 HTTP,它是一问一答的模式,客户端发送请求,服务端返回响应。 有时候也会用 Server Sent Event,它是基于 HTTP 的,客户端发送请求,服务端返回 text/event stream 类型的响应,可
- 174. 基于 Socket.Io 的 Room 实现群聊
上节学了 Nest 里如何创建 WebSocket 服务,这节我们实现下群聊功能。 微信我们可以在不同的群聊里聊天: 如何实现这种功能呢? 这就要用到 socket.io 的 room 功能了。 socket.io 支持加入房间: 可以向对
- 175. 聊天室:需求分析和原型图
学完 WebSocket 之后,我们做个项目来综合练习下。 WebSocket 的项目实战,最容易想到的就是即时通讯(Instant Messaging),也就是聊天室了。 我们每天都在用 QQ、微信,对它们的功能都很熟悉。 我们会实现最精
- 176. 聊天室:技术选型和数据库设计
上节梳理了需求,画了原型图,这节来设计下技术方案。 技术栈 前端部分还是 React + Antd Design,脚手架用 create vite: 后端部分是 Nest + Prisma + Socket.io。 Prisma 是 ORM
- 177. 聊天室:用户注册
这节正式进入开发,我们先来开发注册功能。 创建个 nest 项目: 在 docker desktop 里把 mysql 的容器跑起来: 进入项目,安装 prisma 然后执行 prisma init 创建 schema 文件: 改下 .en
- 178. 聊天室:用户登录
这节我们实现下登录。 在 UserController 添加一个 login 的路由: 创建 src/user/dto/login user.dto.ts: 测试下: 服务端打印了接收的参数。 ValidationPipe 开启 trans
- 179. 聊天室:修改密码、修改信息
这节继续实现下修改密码、修改个人信息的接口: 对应这两个页面: 不过在修改信息之前,需要先实现查询用户信息的接口,用来回显数据。 在 UserController 添加一个 /user/info 接口: 加上 @RequireLogin 装
- 180. 聊天室:好友列表、发送好友申请
用户模块的功能写完了,这节我们来实现添加好友、加入群聊的功能。 好友关系就是用户和用户的多对多关联,保存在好友关系表里。 聊天室有专门的表,加入群聊就是往用户 聊天室的中间表插入一条记录: 我们先来实现好友关系的保存: 在 schema 里
- 181. 聊天室:创建聊天室、加入群聊
好友功能开发完,这节来开发聊天室的功能。 聊天室涉及到两个表: 聊天室表 chatroom: 字段名 数据类型 描述 id INT 聊天室ID name VARCHAR(50) 群聊名 type BOOLEAN 类型(单聊、群聊) crea
- 182. 聊天室:登录、注册页面开发
先不着急开发聊天功能,我们先来写一下前端页面。 先来写下用户注册、登录这两个: 新建个 react 项目: 进入项目目录,把开发服务跑起来: 浏览器访问 http://localhost:5173 可以看到这个界面: 就说明 react 项
- 183. 聊天室:修改密码、信息页面开发
这节继续来写修改密码、修改信息页面: 首先是修改密码的页面 src/pages/UpdatePassword: css 部分如下: 跑起来是这样的: 然后再调用下后端接口。 在 interfaces 添加这两个接口: 更改密码页面里调用下:
- 184. 聊天室:头像上传
上节实现了用户信息的更改,但是是直接修改的文件路径: 这节我们来实现下头像上传。 我们用 minio 来搭 OSS 服务。 把 minio 的 docker 镜像跑起来: 指定本地的某个目录,映射到容器里的 /bitnami/minio/d
- 185. 聊天室:好友∕群聊列表页面
这节来实现下好友/群聊页面: 现在首页是这样的: 需要在 / 下添加一个二级路由: 然后分别实现这几个组件: src/pages/Menu/index.tsx 引入 antd 的 Menu 实现菜单。 渲染的时候根据 useLocation
- 186. 聊天室:添加好友弹窗、通知页面
上节实现了好友、群聊的列表,这节来实现添加好友功能 添加 src/pages/Friendship/AddFriendModal.tsx 然后在 Friednship/index.tsx 里引入下: 添加一个 state 控制弹窗显示隐藏,
- 187. 聊天室:聊天功能后端开发
写完注册、登录、添加好友、群聊列表等前后端代码后,我们继续来开发聊天的功能。 创建一个 websocket 模块: 安装 websocket 的包: 改下 ChatGateway: 监听 joinRoom、sendMessage 消息。 j
- 188. 聊天室:聊天功能前端开发
这节来写下聊天的前端页面: 左侧是聊天室列表,右边是聊天界面。 点击左侧切换聊天室,就可以在不同聊天室聊天。 先写下样式: 样式 index.scss 因为样式比较复杂,我们用到了 sass 安装下: 看下效果: 布局比较简单,整体宽度 8
- 189. 聊天室:一对一聊天
上节实现了聊天界面,但是聊天室不是通过 UI 操作创建的,是我们之前通过接口创建的。 这节就来实现下进入聊天的入口。 也就是这两个: 点击聊天按钮的时候,要创建聊天室,或者查找已有的聊天室,然后带着 id 跳到聊天页面: 聊天页面选中 id
- 190. 聊天室:创建群聊、进入群聊
上节打通了一对一聊天的流程,这节继续打通群聊的流程。 其实现在展示的群聊列表有点问题,应该把一对一的聊天室过滤掉,而且把群聊人数显示出来。 我们改一下: 现在就只剩下群聊了: 然后我们优化下日期展示,加上人数展示,加一个详情按钮: 点击详情
- 191. 聊天室:发送表情、图片、文件
这节来实现下发送表情、图片、文件。 这种 emoji 表情: 有现成的库 emoji mart: 可以试试他的 demo: 我们直接用就行: 安装下: 这样,就可以发表情了: 然后来实现发送图片: 这个和之前的上传图片没啥大的区别。 加一个
- 192. 聊天室:收藏
最后我们再来实现下收藏功能: 聊天的时候可以收藏某条消息,然后在收藏列表查看。 消息分为文字、图片、文件三类,收藏也是这三类。 我们先加一个收藏表: 每个收藏只要记录对应的 chatHistoryId 和 userId 即可。 这里我们同样
- 193. 聊天室:全部功能测试
做完项目之后,我们整体测试一下。 按照之前的需求分析来测: 把 backend 服务跑起来: 然后把 frontend 项目跑起来: 注册 首先填入信息,发送验证码: 注册成功后我们登录下: 登录 刚才注册的账号可以登录。 忘了密码可以修改
- 194. 聊天室:项目总结
学完了 WebSocket 后,我们做了这个聊天室项目。 用户登录之后可以添加别的用户为好友。 发送好友申请后,对方同意之后就会出现在好友列表,然后就可以聊天了。 可以创建群聊,添加别的用户进入群聊。 群聊里可以多人聊天。 聊天记录做了服务
- 195. MongoDB 快速入门
数据库我们学习了 mysql,这节来再来学下 mongodb。 在 docker desktop 搜索 mongo 镜像,然后把它跑起来: 指定容器名、映射的端口号,以及挂载到 /data/db 的本地目录: 这个本地目录是本地的任何一个目
- 196. 使用 Mongoose 操作 MongoDB 数据库
上节我们用了下 mongodb,这节在 node 里操作下。 在 node 里操作 mongodb 我们常用的是 mongoose 这个包。 创建个项目: 进入项目,安装 mongoose 包。 在 Docker Desktop 里把 mo
- 197. GraphQL 快速入门
作为前端开发,想必经常做的事情就是:调接口、画页面、调接口、画页面... 调用的接口大概率是 restful 的,也就是类似这种: /students 查询所有学生信息 /student/1 查询 id 为 1 的学生信息 上面说的是 ge
- 198. Nest 开发 GraphQL 服务:实现 CRUD
上节我们知道了什么是 graphql,它就是通过模式定义语言 SDL(Schema Definition Language) 定义对象和对象之间关系的 schema: 比如: 这个 schema 只是类型,负责实现 schema 对应数据的
- 199. GraphQL + Primsa + React 实现 TodoList
我们经常用 restful 的接口来开发业务。 比如 GET 请求 /students 查询所有学生,/students/1 查询 id 为 1 的学生 发送 POST、PUT、DETETE 请求分别代表增删改。 其实也可以用 GraphQ
- 200. 如何调试 Nest 源码?
前面我们学过如何调试 Nest 项目,那如何调试 Nest 源码呢? 有的同学说,调试 Nest 项目的时候,调用栈里不就有源码部分么? 其实不是的,这部分是编译后的代码: 我们新建个 Nest 项目: 点击 debug 面板的 creat
- Index
Index 技术笔记
- LangChain.js 实践:从 LCEL 到 Agent
理解 LangChain.js 的 Runnable、LCEL、Agent 与 Tool 调用模型,并组合一个可扩展的智能体流程。
- MCP:连接模型与工具的开放协议
了解 MCP 的 Host、Client、Server 架构以及资源、提示词和工具能力。
- NestJS 模块化架构实践
用 Module、Provider 与依赖注入组织可测试、可演进的 Node.js 后端。
- RAG 应用的完整数据链路
从文档切分、向量检索到答案生成,理解 RAG 系统的关键质量控制点。
- React Hooks 深入理解
从状态快照、闭包与副作用同步的角度,系统理解 React Hooks 的工作方式。
- TypeScript 类型系统实践指南
用类型收窄、泛型与可辨识联合提升前端代码的可维护性。
- Webpack 构建性能优化清单
从缓存、并行、模块边界和产物分析入手优化大型前端工程的构建速度。
这里的文章会持续修订,而不是一次性发布后遗忘。
浏览所有文章