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