阶段三:服务端

14 周,服务端技术选型

  • node.js 框架选型:Koa2

  • 数据库:Mysql、MongoDB、Redis

  • 登录校验:JWT

  • 单元测试和接口测试:Jest

  • 上线服务:PM2 + nginx

  • 开发环境效率工具

框架对比

Koa2 更加简单,精简

数据库

  • Mysql 和 Sequelize
  • Mongodb 和 Mongoose
  • Redis

Mysql 适合存储表格形式,格式规整的数据。MongoDB 用于存储文件,格式零散的数据。

数据结构设计

  • JSON 数据存储作品内容,使用 MongoDB
  • 用户信息,作品其它信息,表格形式存储,使用 MySQL
  • 缓存能力,使用 Redis

登录校验

web 常用的登录鉴权方式:

  • JWT
  • Cookie 和 Session
  • SSO 和 OAuth2

JWT

  • JSON Web Token

校验过程:

  1. 客户端输入用户名和密码,传给服务端
  2. 服务端验证成功,返回一段将用户信息加密后的 token 字符串给客户端
  3. 客户端获得 token 之后,自己存储下来
  4. 接下来客户端所有接口请求,都在header中带上这段 token 作为 Authorization 字段
  5. 服务端接收到请求后,拿到 token 会解密,判断

优点:

  • 无需在服务端存储用户信息:服务端不需要在存储用户信息,因为 JWT 中已经包含了所有必要的信息。
  • 成本低、维护简单
  • 不占用服务器内存
  • 多进程、多服务器,不受影响
  • 不受跨域限制

缺点:

  • 无法主动退出:JWT 令牌一旦生成,其有效期内就可以一直使用,无法主动退出。
  • 载荷大小有限制:由于 JWT 令牌需要进行传输和存储,其载荷大小有限制,不适用于存储大量数据的场景。
  • 无法快速封禁某个登录的用户(极少有这种需求情况)

Cookie 校验过程:

  1. 客户端输入用户名和密码,传给服务端
  2. 服务端验证成功,会生成一个Session ID存储在服务端,并在响应头中添加Set-Cookie同时返回给浏览器
  3. 接下来客户端所有接口请求,都自动带上cookie(浏览器的默认行为,Http 协议的规定)
  4. 服务端通过解析 Cookie 中的Session ID,与服务器端存储的 Session 进行对比判断

Session:具体的用户信息存储在 session 中,可以理解为是一个 JSON 数据,放在服务端。cookie 只存储 userid。

优点:用户信息存储在服务端,可以快速封禁某个登录的用户,可以选择 Session

缺点:

  • 占用服务端内存,有硬件成本。
  • 多进程,多服务器时,不好同步,需要将 Session 放到第三方缓存服务中
  • 跨域传递 cookie 时需要特殊配置

JWT 和 Session 的重要区别

  • JWT 用户信息存储在客户端
  • Session 用户信息存储在服务端

SSO 和 OAuth2

  • SSO 企业集团统一登录,然后可以访问集团下面所有系统
  • OAuth2 第三方鉴权登录,比如微信授权登录

短信验证码登录

短信验证码是一种登录的方式,无需注册,无需记住密码。但是要花钱,还要防止攻击,恶意刷短信接口

单元测试

抽离单元,主要用来测试逻辑

单元测试为何难以落实?

因为混淆了单元测试和集成测试,导致单元测试代码中有 Mock。需要服务器启动才能执行的代码,就不再是单元测试,而是集成测试。

  1. 单元测试是针对一个单元,即单一的功能。

  2. 单元测试是针对一段逻辑(比如判断和循环),平铺直叙的代码不用测试。

测试覆盖率,应该看抽离出来的单元模块,而非所有代码。有些代码不适合或不需要单元测试。

还有一个原因是研发流程不规范。

supertest 接口测试

保证安全感。

jest + supertest

单元测试和接口测试的概念需要区分开,不要彼此依赖。

PM2 + Nginx

线上服务关键:稳定 + 高效

PM2 服务只对内开启,nginx 服务作为内部和外部的代理

客户端接口统一先访问 Nginx 服务

日志

  • 日志记录
  • 日志拆分:PM2 日志拆分,nginx 日志拆分,框架日志拆分

开发环境效率工具

  • eslint prettier
  • pre-commit
  • commit 规范

15 周,CI/CD 自动化

  • 使用 GitHub actions
  • 使用 Docker
  • 使用 Docker-compose
  • 自动发布到测试机

使用 GitHub actions

用途:

  • master 分支,自动化测试
  • dev 分支,自动部署到测试服务
  • 提交 tag,自动上线,支持回滚

关于测试流程

  • pre-commit 时执行本地接口测试npm run test:local

  • master push 时执行远程接口测试npm run test:remote

使用 Docker

使用 Docker 构建 node.js 项目

通过Docker-compose搭建开发环境

自动发布到测试机

dev 分支 push 时,自动部署到测试机

  • github actions 监听 git 提交,并执行自定义命令
  • docker 一键部署开发环境

配置测试服务器

  • 创建 work 账号

  • 用 root 登录,创建 work 账号

  • 添加 work 的 sudo 权限

  • 添加登录信任

  • 安装必备软件:git、docker、docker-compose

开放端口

测试机开放需要的端口,让外网可以访问

  • B 端 FE:80
  • B 端 server:8081
  • C 端:8082
  • 统计服务,收集日志:8083
  • 统计服务 OpenAPI:8080
  • admin FE:8085
  • admin server: 8084

线上环境不需要开发这么多端口,只需要使用 nginx 反向代理

梳理思路

  • 使用 github actions 监听 dev 分支 push

  • 登录测试机,获取最新 dev 分支代码

  • 重新构建镜像 docker-compose build editor-server

  • 重启所有容器 docker-compose up -d

第 16 周 编辑器服务端基础 API 开发

  • 技术方案设计和基础功能开发

技术方案设计和基础功能开发

需求指导设计,设计指导开发,无设计不开发。

  • 1.服务端技术方案设计的方法
  • 2.B 端和编辑器基本功能 API

1.服务端技术方案设计的方法

  • 1.1 接口设计
  • 1.2 数据库设计
  • 1.3 选择 Restful API 而非 GraphQL

1.1 接口设计

在需求评审的时候,需要思考要用到哪些接口,接口有哪些输入和输出,接口是否合理,接口是否能够实现。

需要具体的设计出每个接口的输入与输出。

可以使用工具做设计,比如 postman

B 端功能拆分

  • 用户信息
  • 模板管理
  • 我的作品管理
  • 编辑器
  • 渠道
  • 工具类

用户信息

  • 获取手机短信验证码(思考输入什么,输出什么)
  • 登录(包含注册)
  • 获取用户信息
  • 修改用户信息

模板管理:

  • 首页推荐模板列表,分页,搜索
  • 获取单个模板信息
  • 我的模板列表,分页,搜索

作品管理:

  • 创建空白作品
  • 复制作品
  • 删除作品
  • 恢复作品
  • 转赠作品
  • 我的作品列表,分页,搜索
  • 我的回收站列表,分页,搜索

编辑器:

  • 查询单个作品信息
  • 保存作品
  • 预览作品
  • 发布为作品
  • 发布为模板

渠道:

  • 创建渠道

  • 删除渠道

  • 修改渠道名称

  • 获取单个作品的所有渠道

  • 工具类:

  • 上传图片

统一的输出格式

{
  "errno": 0,
  "data": {},
  "message": ""
}
1
2
3
4
5

1.2 数据库设计

需要存储的数据:

  • 用户
  • 作品/模板
  • 渠道

数据之间的关系:

一个用户可以创建很多个作品(1 对多关系),一个作品可以创建很多个渠道(1 对多关系),一个作品只对应一个内容(1 对 1 关系)。

image

数据表设计

用户:

类型注释
usernamevarchar用户名
passwordvarchar密码(保留字段,暂时用不到)
phoneNumbervarchar手机号
nickNamevarchar昵称
genderint性别
picturevarchar用户头像

作品/模板:

同上,省略...

类型注释
uuidvarcharh5 url 中使用,隐藏真正的 id,避免被爬
contentIdvarchar未发布内容 id,内容存储在 MongoDB 中
publishContentIdvarchar布内容 id,内容存储在 MongoDB 中,未发布的为空
isTemplateboolean是否模板
statusint状态:0=删除,1=未发布,2=发布,3=强制线下

渠道:

同上,省略...

作品内容

  • 未发布
  • 已发布

MongoDB

{
  // 页面的组件列表
  components: [Object],
  // 页面的属性
  props: Object,
  // 配置信息
  setting: Object,
}
1
2
3
4
5
6
7
8

sequelize Model 以及关联关系

// 和 UserModel 建立关系
Work.belongsTo(UserModel, {
  foreignKey: 'author',
  targetKey: 'username', // 对应 UserModel.username 属性
});
1
2
3
4
5

mongoose Schema 和 Model

  • 未发布的内容:workContent
  • 已发布的内容:workPublishContent

B 端-server 整体架构图

完成上面步骤之后,再设计出整体架构图,结合接口设计,数据库设计,数据格式设计,将各个功能和模块抽象成一张图来表示。

结构是一层又一层,每一个模块使用不同颜色标记,越底层越抽象,底层的支撑上层的,最上层的是对外开放的路由。

image

biz-editor-server 端技术方案

评审技术方案设计前,最后整理出一份技术方案文档,让人能够对这个系统有一个初步的整体认识。

范围:

  • B 端 + 编辑器 server
  • 多项目关系图,当前的范围,与其它模块的关系

技术选型:

  • 框架
  • 数据库
  • 登录校验
  • 单元测试
  • 发布上线
  • CI/CD

整体架构设计:

  • 整体架构图

接口设计:

  • 范围、各个接口列表
  • 接口输入和输入(只评审关键的、有疑问的接口)

数据库设计:

  • 数据关系
  • 数据表

基本功能开发

  • 登录功能
  • 用户信息接口
  • 作品接口
  • 模板接口

登录功能

短信功能,初次发短信,再次发短信。

考虑费用,禁止频繁发送,短信服务的报警,稳定性。

使用短信验证码直接登录,比用户名和密码登录更加简单方便,用户名和密码登录还需要配套功能,比如忘记密码、修改密码,这些功能做起来也很费力,而且也要发短信。

Last Updated: 2023/6/28 09:50:59
Contributors: licong96