# 一句话简介
- 基于 Node.js:Node.js 模块
- 下一代:蚕食第一代 Web 框架 Express 的市场
- Web 框架
# 洋葱 🧅 模型
// 演示洋葱模型
app.use(async (ctx,next) => {
console.log('1-1')
await next()
console.log('1-2')
})
app.use(async (ctx,next) => {
console.log('2-1')
await next()
console.log('2-2')
})
app.use(async (ctx,next) => {
console.log('3-1')
await next()
console.log('3-2')
})
app.use(async (ctx,next) => {
console.log('4-1')
await next()
console.log('4-2')
})
app.use(async (ctx) => {
console.log('5')
ctx.body = 'Hello World'
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 路由是什么
- 决定了不同 URL 是如何被不同地执行的
- 在 Koa 中,是一个中间件
# 为什么要用路由?
- 如果没有路由,会怎么样?
- 所有请求都做了相同的事情
- 所有请求都会返回相同的结果
# 状态 🐴
- 运行时错误,都返回 500
- 逻辑错误 404(不存在)412(先决条件失败)422(无法处理的实体,参数格式不对等等)
# 为什么要用错误处理
- 防止程序挂掉
- try catch finally
- 告诉用户错误信息
- 便于开发者调试
# koa-json-error 进行错误处理中间件
# koa-parameter 校验参数
# 什么是 NoSQL ?
- 对不同于传统的关系型数据库的数据管理系统的统称
# NoSQL 数据库的分类
- 列存储 (HBase)
- 文档存储 (MongoDB)
- key-value 存储(Redis)
- 图存储 (FlockDB)
- 对象存储 (db4o)
- XML 存储 (BaseX)
# 为什么要用 NoSQL
- 简单(没有原子性、一致性、隔离性等复杂规范)
- 便于横向拓展
- 适合超大规模数据的存储
- 很灵活地存储复杂结构的数据 (Schema Free)
# 为什么要用 MongoDB?
- 性能好(内存计算)
- 大规模数据存储(可拓展性)
- 可靠安全 (本地复制、自动故障转移)
- 方便存储复杂数据结构(Schema Free)
# 云 MongoDB
MongoDB Atlas
mongodb+srv://qile:<password>@cluster0.cce0o.mongodb.net/myFirstDatabase?retryWrites=true&w=majority
1
# Session 简介
# Session 的优势
- 相比 JWT,最大优势就在于可以主动清除 session 了
- session 保存在服务器端,相对较为安全
- 结合 cookie 使用,较为灵活,兼容性较好
# session 的劣势
cookie + session 在跨域场景表现并不好
是因为设置 cookie 的时候 并不只设置 session id 还有 domain 表示 cookie 只有这个域名下才会生效
如果是分布式部署,需要做多机共享 session 机制。
因为 session 一般都保存在内存中 多机部署时要考虑 session 的共享
基于 cookie 的机制很容易被 CSRF (跨站请求伪造)
查询 session 信息可能会有数据库查询操作
可能是将 sessionId 给客户端,那 session 的完整信息就会存在数据库
sessionStorage: 仅在当前会话下有效,关闭页面或浏览器后被清除
localStorage:除非被清除,否则永久保存,因为它是存在本地的内存中
# 什么是 JWT
- JSON Web Token 是一个开放标准(RFC7519)
- 定义了一种紧凑并且独立的方式,可以将各方之间的信息作为 JSON 对象进行安全传输
- 该信息可以验证和信任,因为是经过数字签名的
# JWT 的构成
- 头部(header)
- 有效载荷 (Payload)
- 签名(Signature)
# JWT vs Session
- 可拓展性 水平拓展(其实就是加服务器) 垂直拓展(增加每台服务器的硬件性能 eg 磁盘、内存、cpu)
- 安全性 XSS(跨站脚本攻击,要签名、加密)CSRF (跨站请求伪造、cookie) 重放攻击 中间人攻击(https)
- RESTful API
- 性能 比 session 弱 JWT 比较大 http 请求开销大 SessionId 又需要让后端去查对应的数据
- 时效性 比 session 差一点 只有等过期了才能销毁 但 session 可以在后端在程序中销毁
# 在 Nodejs 中使用 JWT
- 安装 jsonwebtoken 这个 npm 包
- 签名
- 验证
# 在 Nodejs 中使用 koa-jwt 来鉴权
- 使用这个 koa-jwt 来对接口做鉴权
# 上传图片的需求场景
- 用户头像
- 封面图片
- 问题和回答中的图片
- 话题图片
# 上传图片的功能点
- 基础功能:上床图片、生成图片链接
- 附加功能: 限制上传图片的大小与类型、生成高中低三种分辨率的图片链接、生成 CDN
# 上传图片的技术方案
- 阿里云的 OSS 等云服务,推荐在生产环境
- 直接上传到服务器,不推荐在生产环境下中使用
# 使用 koa-body 来获取上传的文件
- 安装 koa-body。替换 koa-bodyparser
- 设置图片上传目录
- 使用 postman 上传文件
# 使用 koa-static 生成图片链接
- 生成了静态服务
- 设置静态文件目录
- 生成图片链接
# 用户信息的 schema 设计
# 关注与取消关注
- 要理解当前用户和被关注的人之间的关系
- 我关注了一个人,那么我就是他的粉丝
- 可以推导出用户粉丝就是关注了我的人
# 校验用户存在与否的中间件
# 话题模块功能
- 话题的增改查
- 分页、模糊查询 .limit() .skip()
- 用户属性中的话题引用
- 关注/取消关注话题,用户关注的话题列表
# 模糊搜索 🔍
- find({ name: new RegExp(ctx.query.q) })
# 用户属性中的话题引用
- { type: Schema.Types.ObjectId, ref: "Topic" }
- populate('a b c')
- 使用话题引用替代部分用户属性
# 实现关注话题逻辑
- 用户-话题多对多关系
# 问题模块功能点
- 问题的增删改查
- 用户的问题列表(用户-问题一对多关系)
- 话题的问题列表+问题的话题列表(话题-问题多对多关系)
- 关注/取消关注问题
# 用户-问题一对多关系设计实现
- CURD 接口
- 显示用户的问题列表接口
# 话题-问题多对多关系设计
- 实现问题的话题列表接口
- 实现话题的问题列表接口
- 在问题中对话题进行关联,因为一个问题可能最对关联 5-10 个话题,但一个话题可能有成千上万的问题,所以不利于后端的接口字段的数据存储的大小。MongoDB 对每个字段的存储大小有限制
# 答案模块功能点
- 答案的增删改查
- 问题-答案/用户-答案一对多关心
- 赞/踩答案
- 收藏答案
# 答案接口用二级嵌套的方式实现 CURD
- /questions/:id/answers
- 因为答案只能是某一个问题的
- 问题有很多答案,但答案只针对某一个问题
# 互斥关系的赞/踩答案接口设计与实现 6 个接口
- 设计数据库 Schema
- 在用户的 Schema 放两个字段用于关联赞和踩的答案
- 互斥关系其实就是踩的时候要取消赞/赞的时候取消踩 (可以利用路由的中间件来实现)中间件应该要加 next
# RESTful 风格的收藏答案接口
# 问题-答案-评论模块三级嵌套的增删改查接口
- 参考 github 的评论接口:GET /repos/:owner/:repo/issues/:umber/comment
- const router = new Router({ prefix: "/questions/:questionId/answers/:answerId/comments" })
# 一评论与二级评论接口的设计与实现
# 服务器的操作
- ssh 登录服务器 ssh root@ip
- 安装 Git,下载代码到服务器
- 安装 NodeJs,运行程序
# 用 Nginx 实现端口转发
# 使用 PM2 管理进程
- 安装 PM2
- npm i pm2 -g -d
- 使用 PM2 启动、停止、重启、重载程序
- pm2 start appName
- pm2 stop appName
- pm2 restart appName
- pm2 reload appName
- NODE_ENV=production pm2 restart app --update-env --log-date-format "YYYY 年 MM 月 DD 日 HH:mm"
- 使用 PM2 日志、环境变量管理功能
- NODE_ENV=production pm2 start app --update-env