Koa学习笔记01

2021/6/26 Node.jsKoa

# 一句话简介

  • 基于 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

# 路由是什么

  • 决定了不同 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工作原理

# 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

# 使用企业级 Node.js Egg.js

# 掌握多进程编程知识

# 学习使用日志和性能监控

Last Updated: 2022/8/30 上午10:39:18