# 一、项目目标

  • 理解 RESTful API 的 6 个限制和若干最佳实践
  • 掌握 Koa2、Postman、MongoDB、JWT 等技术
  • 运用上述技术搭建仿知乎 RESTful API
  • 掌握阿里云线上部署方法

# 二、REST

# what

  • 万维网软件架构风格
  • 用来创建网络服务

# Why

  • Representational State Transfer - 数据在互联网传输时的表现形式
  • Representational 数据的表现形式(JSON、XML...)
  • State 当前的状态或者数据
  • Transfer 数据传输

# 6个限制

# 1. 客户端-服务端(Client-Server)

  • 关注点分离
  • 服务端专注数据存储,提升了简单性
  • 前端专注于用户界面,提升了可移植性

# 2. 无状态

  • 所有用户会话信息都保存在客户端
  • 每次请求必须包括所有信息,不能依赖上下文信息
  • 服务端不用保存会话信息,提升了简单性、可靠性、可见性

# 3. 缓存

  • 所有服务端响应都要被标为可缓存或不可缓存
  • 减少前后端交互,提升了性能

# 4. 统一接口(重要)

  • 接口设计尽可能统一通用,提升了简单性、可见性
  • 接口与实现解耦,使前后端可以独立开发迭代

# 5. 分层系统

  • 每层只知道相邻的一层,后面隐藏的就不知道了
  • 客户端不知道是和代理还是真实服务器通信
  • 其它层:安全层、负载均衡层、缓存层等

# 6. 按需代码(可选)

  • 客户端可以下载运行服务端传来的代码(比如 JS 代码,通过 eval 执行)
  • 通过减少一些功能,简化了客户端

# 统一接口的限制

# 1. 资源的标识

  • 资源是任何可以命名的事物,比如用户、评论等
  • 每个资源可以通过 URI 被唯一的标识

# 2. 通过表述来操作资源

  • 表述是 Representation,比如 JSON、XML等
  • 客户端不能直接操作(比如通过 SQL)服务端资源
  • 客户端应该通过表述(比如 JSON)来操作资源

# 3. 自描述消息

  • 每个消息(请求或响应)必须提供足够的信息让接受者理解
  • 媒体类型(application/json、application/xml)
  • HTTP 方法:GET(查)、POST(增)、DELETE(删)
  • 是否缓存(Cache-Control)

# 4. 超媒体作为应用状态引擎

  • 点击链接跳转到另一个网页

# RESTful API

# 1. 组成

  • 基本的 URI
  • 标准的 HTTP 方法,如 GET、POST、PUT等
  • 传输的数据的媒体类型,如 JSON、XXML

# 2. 设计规范

  • URI 使用名词,尽量用复数,如 /users
  • URI 使用嵌套表示关联关系,如 /users/12/repos/5
  • 使用正确的 HTTP 方法,如 GET/POST/PUT/DELETE
  • 不符合 CRUD 的情况:POST+动词/action/子资源

# 3. 响应设计规范

  • 查询,可通过参数限定数据范围
  • 分页
  • 字段过滤,可通过指定字段限定返回哪些字段
  • 状态码
  • 错误处理信息
  • 增删改查返回响应:(最佳实践)
    • 查 - 查找的内容
    • 增、改 - 增、改的内容
    • 删 - 204状态码

# 4. 安全

  • HTTPS
  • 鉴权,通过登录获取用户信息
  • 限流,请求头部记录请求次数,超过限额时报错

# 5. 开发者友好

  • API 文档
  • 超媒体

# 三、Koa

# 1. 一句话简介

基于 Node.js 的下一代 Web 框架

# 2. 洋葱模型

  • async、await
  • ctx、next

# 3. 常用 koa 中间件

  • nodemon - 热更新
  • koa-router - 路由(需实例化 new Router(),并注册到koa上 app.use(router.routes()))
  • Koa-bodyparser - 获取请求体,仅支持 JSON 和 form 格式的请求体
  • koa-body - 获取请求体,不仅支持 JSON 和 form,还支持文件格式,可以应对文件(图片等)上传的场景
  • Koa-static - 生成一个静态服务,可通过配置,指定一个文件夹作为静态服务的目标目录,然后就可以通过http访问到该文件夹下的文件了
  • Koa-json-error - 错误处理
  • Cross-env - 跨平台设置环境变量
  • Koa-parameter - 校验请求参数
  • Mongoose - 连接mongodb数据库
  • jsonwebtoken - 生成JWT以及验证
  • koa-jwt - 用户认证和授权

# 4. 常用状态码

  • 404 请求不存在
  • 405 请求方法不允许(有能力实现,但是不允许你这样请求,例如 koa-router 有能力实现 put 方法,但是不允许这个接口这样用)
  • 501 请求方法不支持(没有能力支持该请求方法,例如 koa-router 仅支持常用方法,无法支持 link 等不常用方法)
  • 412 先决条件失败(如 路由参数值超出有效范围)
  • 500 运行时错误(如 a.b a为undefined)
  • 422 无法处理的实体(请求参数校验未通过)
  • 409 已存在,导致冲突
  • 401 不存在
  • 403 未授权

# 5. 路由存在的意义

  • 处理不同的 URL
  • 处理不同的 HTTP 方法
  • 解析 URL 上的参数

# 6. http options 方法

作用:

  • 检测接口所支持的请求方法
  • CORS 中的预检请求

koa-router 中的 allowedMethods 方法的作用:

  • 响应 options 方法,返回该接口所支持的请求方法
  • 相应地返回 405(不允许)和 501(没实现)

# 7. 控制器

  • 拿到路由分配的任务,并执行
  • 在 koa 中,控制器是中间件
  • 获取 HTTP 请求参数
  • 处理业务逻辑
  • 发送 HTTP 响应

# 8. 获取 HTTP 请求参数

  • Query String,如 ?q=keyword,往往是可选的参数,长度有限制,不安全
  • Router Parames,如 /users/:id,路由参数是必选的
  • Body,如 { name: 'lilei' }
  • Header,如 Accept、Cookie

# 9. 发送 HTTP 响应

  • 发送 Status,如 200/400 等
  • 发送 Body,如 { name: 'lilei' }
  • 发送 Header,如 Allow、Content-Type

# 10. 编写控制器的最佳实践

  • 每个资源的控制器放在不同的文件里
  • 尽量使用类 + 类方法的形式编写控制器
  • 严谨的错误处理

# 11. Vs code 断点调试

  • 打开带执行代码,点击 F5
  • 在需要断点处设置断点
  • 请求接口,查看断点处参数

# 12. 异常状况有哪些

  • 运行时错误,都返回 500
  • 逻辑错误,如 找不到(404)、先决条件失败(412)、无法处理的实体(参数格式不对,422)等

# 四、NoSQL 数据库

# 1. 分类

  • 列存储(HBase)
  • 文档存储(MongoDB)- 按JSON存储
  • Key-Value存储(Redis)
  • 图存储(FlockDB)
  • 对象存储(db4o)
  • XML存储(BaseX)

# 2. 特点

  • 简单(没有原子性、一致性、隔离性等复杂规范)
  • 便于横向拓展
  • 适合超大规模数据的存储
  • 很灵活的存储复杂结构的数据(Schema Free)

# 3. MongoDB

# 特点

  • 性能好(内存计算)
  • 支持大规模数据存储(可拓展性好)
  • 可靠安全(本地复制、自动故障转移)
  • 方便存储复杂数据结构(Schema Free )

# 安装 ——> 云MongoDB ——> MongoDB Atlas

  • 注册用户
  • 创建集群(包含很多集合)
  • 添加数据库用户
  • 设置IP地址白名单
  • 获取连接地址

MongoDB Atlas 账号 z_jerry2016@163.com 集群 zhihu 数据库用户 jerry 密码 jerry123

# Mongoose 连接 MongoDB

  • 连接 .connect()
  • 创建 Schema new Schema()
  • 创建集合 model('User', userSchema)
  • 增删改查
    • 查 .find()
    • 查找特定 findById
    • 增 new User(ctx.request.body).save()
    • 改 findByIdAndUpdate
    • 删 findByIdAndRemove

# 五、JWT

# 1. Session

  • 认证:让服务器知道你是谁
  • 授权:服务器授予的什么能做什么不能做的权利
  • 原理:
    • 客户端向服务端发送用户名、密码等信息请求登录
    • 服务端接收到用户名、密码并查询数据库获取其它用户信息(认证、授权等),用这些信息生成Session数据存入内存或内存数据库(例如radis)中,每条Session数据对应一个Session ID,服务端向客户端发送Session ID(有时会将整个Session数据加密成Session ID,从而无需保存在服务端,就可直接从SessionID中解密出用户信息)
    • 客户端将Session ID存在Cookie中,每次发送请求都会自动携带Cookie中的Session ID
    • 服务端接收到Session ID,会到内存或内存数据库(例如radis)中查找对应的Session数据,并解析出用户信息,从而获取认证、授权等信息,最后对请求进行响应
    • 客户端想退出登录:仅需删除Cookie中的Session ID即可
    • 服务端想强制用户退出:仅需删除内存或内存数据库(例如radis)中的Session数据即可
  • 优势:
    • 相比于JWT(仅将Token存在客户端),最大优势在于服务端可以主动清楚Session(因为Session数据存在服务端)
    • session数据保存在服务端,相对较安全
    • 结合Cookie使用,较为灵活,兼容性较好
  • 劣势:
    • Session + Cookie 在跨域场景下表现不好
    • 如果是分布式部署,需要做多机共享Session机制
    • 基于Cookie的机制很容易被CSRF
    • 查询Session信息可能会有数据库查询操作,带来性能问题

# 2. JWT

  • Json Web Token是一个开放标准
  • 定义了一种紧凑且独立的方式,可以将各方之间的信息作为JSON对象进行传输
  • 该JSON对象是可以被验证和信任的,因为是经过数字签名的
  • 构成:
    • 头部(Header):token方式、加密算法
    • 有效载荷(payload):有效信息,进行base64UrlEncode()编码,可加密
    • 签名(Signature):对Header和Payload部分进行签名,保证token在传输的过程中没有被篡改或者损坏
  • 工作原理:
    • 客户端向服务端发送用户名、密码等信息请求登录
    • 服务端接收到用户名、密码并查询数据库获取其它用户信息(认证、授权等),并将这些信息作为JWT的Payload,连同Header一起进行编码和加密,并添加Signature形成JWT,作为响应结果返回给客户端
    • 客户端接收到JWT后,保存在 SessionStorage或者LocalStorage中,之后每次发送请求都会在请求头中以 Authorization: Bearer ...JWT... 的形式携带JWT信息
    • 服务端接收到JWT,进行解密解码并验证有效性获知用户信息,并返回请求结果
    • 客户端想退出登录:仅需删除SessionStorage或者LocalStorage中的Session ID即可
    • 由于JWT保存在客户端,服务端无法强制客户端退出登录
  • JWT vs. Session
    • 可拓展性(横向拓展) JWT更优
    • 安全性
      • xss js可修改sessionStorage、localStorage中的JWT,可通过签名和加密来防范
      • CSRF 跟cookie相关
      • 中间人攻击 使用https来防范
    • RESTful API 其中一个限制是“无状态”,所以选择JWT而不是Session
    • 性能
      • JWT 传输数据量大,相比Session是通过空间换取时间
      • Session 需要通过SessionId查询数据库获取真实信息
    • 时效性
      • JWT时效性差,因为对于服务端,只能等到过期时间JWT才会销毁,而Session保存在服务端,服务端可以主动销毁
  • Node 中使用 JWT
    • jsonwebtoken 的基本使用
      • 生成 token = jwt.sign({name: 'jerry', age: '18'}, 'secret')
      • 验证 jwt.verify(token, secret)
    • Koa-jwt 内置了 jsonwebtoken,使用更便捷

# 六、上传图片

# 1. 功能点

  • 基本功能:上传图片、生成图片链接
  • 附加功能:限制上传图片的大小与类型、生成高中低三种分辨率的图片链接、生成CND

# 2. Koa-static - 生成一个静态服务

# 七、个人资料

# 1. schema设计

# 2. 参数校验

# 3. 字段过滤

  • 设计 schema 默认隐藏部分字段
  • 通过查询字符串显示隐藏字段

# 八、关注与粉丝

# 1. 需求分析

  • 关注、取消关注
  • 获取关注人、粉丝列表(用户-用户 多对多关系)

# 2. schema 设计

  • mongoDB 规定一行数据量超过 4M 就代表数据结构设计不合理
  • 一个用户可以关注多个用户(1对多),一个用户也可以被多个用户关注(多对1)。设想,一个大V可能有100万粉丝,显然按多对1设计会存在数据量过大的问题,但一个用户关注的用户量不会很多(顶多关注几千个),所以按1对多来设计比较合理。
  • 基于1对多的数据结构,获取粉丝即可变相的请求“关注了我的用户”

# 3. 接口实现

  • 获取关注人(关注了谁)、粉丝列表接口
  • 关注、取消关注接口

# 九、话题接口

# 1. 需求分析

  • 话题的增改查
  • 分页、模糊搜索
  • 用户属性中的话题引用
  • 关注/取消关注话题、用户关注的话题列表

# 2. schema 设计

# 3. 分页

  • query传参
  • mongoose 的语法糖 limit() 和 skip() 可实现分页

# 4. 模糊搜索

  • query传参
  • mongoose 的语法糖 正则表达式

# 5. 话题关注与取消关注接口

  • 用户-话题多对多关系

# 十、问题接口

# 1. 一对多接口设计

# 2. 话题 - 问题多对多关系设计与实现

  • 问题的话题列表
    • 一个问题的话题是有限的,但话题的问题可能是非常多的,所以我们在问题Model的Schema中添加 topics字段
  • 话题的问题列表

# 十一、答案接口

# 1. 功能点

  • 增删改查
  • 问题-答案/用户-答案——一对多
  • 赞/踩答案
  • 收藏答案

# 2. 二级嵌套的增删改查

# 3. 互斥关系的赞/踩答案接口设计与实现

# 十二、评论接口

# 1. 三级嵌套的增删改查

# 2. 一级评论、二级评论

# 十三、阿里云安装Git和Node

# 1. 登录阿里云服务器

命令行输入 ssh 服务器用户名@公网IP

# 2. 下载Git

查看git官网,不同服务器系统的安装方式不同

# 3. 将代码克隆到服务器

git clone 代码的http地址

# 4. 服务器上安装 node.js

使用NodeSource(github搜索)

# 5. 用 nginx 实现端口转发

外网3000端口不开放,无法访问3000端口。外网只开放了80端口,但我的程序无法绑定到80端口,此时可用nginx将外网的80端口转发到内网的3000端口上。

  • 安装 nginx

  • 配置 nginx,把外网80端口转发到内网3000端口

    • vim 配置文件。 打开配置文件
    • i。进入编辑状态
    • esc按键。退出编辑状态
    • :wq。保存并退出
  • 检查配置是否有误

    nginx -t

  • 重启nginx

    Service nginx rstart 或 service nginx reload

# 6. 使用 PM2 管理进程(守护进程)

  • 安装 PM2。 npm i pm2 -g
  • 使用pm2启动程序。pm2 start app
  • 停止程序。pm2 stop app
  • 重启重启。pm2 restart app. pm2 reload app
  • 添加环境变量。NODE_ENV=production pm2 start app --update-env
  • 查看日志 pm2 log
最后更新时间: 3/28/2021, 9:04:52 PM