这一章只有一节,也只有一个目的,就是告诉你这门课程讲了什么,最终做出的效果,以及学习这门课程你需要先掌握哪些技术。
- 课程目标
- 理解RESTful API的6个限制和若干最佳实践
- 掌握Koa2、Postman、 MongoDB、JWT等技术
- 运用上述技术搭建仿知乎RESTful API
- 掌握阿里云线上部署方法
- 功能技术分析
- RESTful API理论
- Koa2
- Postman
- MongoDB
- JWT
- 阿里云部署
- 前置知识
- Node.js 基础
- ES6、ES7 基础
- 重难点分析
- RESTful API理论
- JWT认证原理
- 复杂的数据库关系(一对多、多对多等)
- 课程建议
- 理论部分做到自问自答
- 实战部分做到举一反三
- 不止于本课程,学习更多技术
本章以全球最大的同性社交社区 GitHub 的 RESTful API 十几个最佳实践为例,让你掌握最完整的 RESTful API 理论
REST:Representational State Transfer
- Representational: 数据的表现形式(JSON、XM.....)
- State: 当前状态或者数据
- Transfer: 数据传输
- 客户一服务器( Client一Server )
- 关注点分离
- 服务端专注数据存储,提升了简单性
- 前端专注用户界面,提升了可移植性
- 无状态( Stateless )
- 所有用户会话信息都保存在客户端
- 每次请求必须包括所有信息,不能依赖上下文信息
- 服务端不用保存会话信息,提升了简单性、可靠性、可见性
- 缓存( Cache )
- 所有服务端响应都要被标为可缓存或不可缓存
- 减少前后端交互,提升了性能
- 统一接口( Uniform Interface )
- 接口设计尽可能统一通用,提升了简单性、可见性
- 接口与实现解耦,使前后端可以独立开发迭代
- 分层系统( Layered System )
- 每层只知道相邻的一层,后面隐藏的就不知道了
- 客户端不知道是和代理还是真实服务器通信
- 其他层:安全层、负载均衡、缓存层等
- 按需代码( Code一On一Demand可选 )
- 客户端可以下载运行服务端传来的代码(比如JS)
- 通过减少一些功能,简化了客户端
- 资源的标识
- 资源是任何可以命名的事物,比如用户、评论等
- 每个资源可以通过URI被唯一地标识
- 通过表述来操作资源
- 表述就是Representation,比如JSON、XML等
- 客户端不能直接操作(比如SQL)服务端资源
- 客户端应该通过表述(比如JSON)来操作资源
- 自描述消息
- 每个消息(请求或响应)必须提供足够的信息让接受者理解
- 媒体类型(application/json、application/xml)
- HTTP方法:GET(查)、POST(增)、DELETE(删)
- 是否缓存: Cache-Control
- 超媒体作为应用状态引擎
- 超媒体:带文字的链接
- 应用状态:一个网页
- 引擎:驱动、跳转
- 合起来:点击链接跳转到另一个网页
- 基本的URI ,如https://api.github.com/users
- 标准HTTP方法,如GET, POST, PUT, PATCH, DELETE
- 传输的数据媒体类型,如JSON, XML
Methed | URI | Meaning |
---|---|---|
GET | /users | 获取user列表 |
GET | /users/1 | 查看user1 |
POST | /users | 新建一个user |
PUT | /users/1 | 更新 user 1 |
DELETE | /users/1 | 删除 user 1 |
- 请求设计规范
- URI使用名词,尽量用复数,如/users
- URI使用嵌套表示关联关系,如/users/12/repos/5
- 使用正确的HTTP方法,如GET/POST/PUT/DELETE
- 不符合CRUD的情况:POST/action/子资源
- 相应设计规范
- 查询
- 分页
- 字段过滤
- 状态码
- 错误处理
- 安全
- HTTPS
- 鉴权
- 限流
- 开发者友好
- 文档
- 超媒体
本章将带你了解什么是 Koa 框架,搭建 Koa 框架的开发环境,并且编写第一个 Koa 框架的程序。不仅如此,重点是还要带你理解什么是 Koa 中间件以及经典的洋葱模型。
基于Node.js的下一代web开发框架
- 基于Node.js: Node.js模块
- 下一代:蚕食第一代Web框架Express的市场
- Web框架:不是命令行工具、不是算法
Koa是一个新的web框架,由Express幕后的原班人马打造,致力于成为web应用和API开发领域中的一个更小、更富有表现力、更健壮的基石。通过利用async函数, Koa帮你丢弃回调函数,并有力地增强错误处理。Koa并没有捆绑任何中间件,而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。
- 由Express幕后的原班人马打造
- Web应用和API开发领域
- 更小、更富有表现力、更健壮
- 利用async函数,丢弃回调函数
- 增强错误处理:try catch
- 没有捆绑任何中间件
- 快速而愉快地编写程序
操作步骤
- 初始化项目
- 安装Koa
- 编写Hello World
- 学习自动重启
在合适的位置新建项目文件夹
在项目目录下执行npm init
npm i koa --save
新建JS文件,比如index.js
npm i nodemon --save-dev
由于是本地安装所以并不能在项目文件夹下直接执行nodemon index.js
,我们在package.json
中添加如下命令:
"scripts": {
"start": "nodemon index.js"
}
操作步骤
- 学习 async await
- 学习编写Koa中间件
- 学习洋葱模型
获取两个GitHub的接口并返回
上节代码打印的顺序为:1 3 5 4 2,类似一个🧅
本章主要讲解 Koa 框架的路由。和其他课程的区别在于,不仅要学习 Koa 框架本身的路由用法,还要学习实现 REST 风格的路由用法。
- 决定了不同URL是如何被不同地执行的
- 在Koa中,是一个中间件
- 如果没有路由,会怎么样?
- 路由存在的意义
- 所有请求都做了相同的事
- 所有请求都会返回相同的结果
- 处理不同的URL
- 处理不同的HTTP方法
- 解析URL上的参数
操作步骤
- 处理不同的URL
- 处理不同的HTTP方法
- 解析URL上的参数
操作步骤
- 更优雅地实现路由基本功能
- 演示一些高级路由功能,如前缀、多中间件
- 这是一道面试题
- 帮助理解koa-router的allowedMethods的作用
- 检测服务器所支持的请求方法
- CORS中的预检请求
- 响应options方法,告诉它所支持的请求方法
- 相应地返回405(不允许)和501(没实现)
操作步骤
- 实现增删改查
- 返回正确的响应
本章主要讲解 Koa 框架的控制器部分的内容。从如何获取 HTTP 的请求参数,到发送 HTTP 的响应,一应俱全。让你明白目录结构是怎么来设计的更合理。
- 什么是控制器?
- 拿到路由分配的任务,并执行
- 在Koa中,是一个中间件
- 为什么要用控制器?
- 获取HTTP请求参数
- 处理业务逻辑
- 发送HTTP响应
- 获取HTTP请求参数
- Query String, 如
?q=keyword
, 一般为可选 - Router Params, 如
/users/:id
, 一般为必选 - Body, 如
{ name: "李雷" }
- Header, 如
Accept
,Cookie
- Query String, 如
- 发送HTTP响应
- 发送Status,如
200
/400
等 - 发送Body,如
{ name:"李雷" }
- 发送Header,如
Allow
、Content-Type
- 发送Status,如
- 编写控制器最佳实践
- 每个资源的控制器放在不同的文件里
- 尽量使用 类+类方法 的形式编写控制器
- 严谨的错误处理
操作步骤
- 学习断点调试
- 获取query (ctx.query)
- 获取router params (ctx.params)
- 获取body (ctx.request.body)
- 获取header (ctx.header)
VSCode中按F5进入调试并设置断点
koa不支持解析请求体,需要引入中间件koa-bodyparser
npm i koa-bodyparser --save
操作步骤
- 发送 status
- 发送 body
- 发送 header
- 实现用户的增删改查
ctx.status = 204;
ctx.body = '<h1>这是主页</h1>';
操作步骤
- 将路由单独放在一个目录
- 将控制器单独放在一个目录
- 使用 类+类方法 的方式组织控制器
新建总文件夹/app
,并修改入口文件
"scripts": {
"start": "nodemon app"
}
- /app
- /routes
- home.js
- users.js
- /controllers
- home.js
- users.js
- /routes
本章主要讲解多种方案的错误处理。主要分三方面,一是 Koa 框架自带的错误处理,一是编写错误处理中间件,一是使用优秀的错误处理中间件。
- 什么是错误处理?
- 编程语言或计算机硬件里的一种机制
- 处理软件或信息系统中出现的异常状况
- 异常状况有哪些?
- 运行时错误,都返回500
- 逻辑错误,如找不到(404)、先决条件失败(412)、无法处理的实体(参数格式不对,422)等
- 为什么要用错误处理?
- 防止程序挂掉
- 告诉用户错误信息
- 便于开发者调试
操作步骤
- 制造404、412、500三种错误
- 了解Koa自带的错误处理做了什么
操作步骤
- 自己编写错误处理中间件
- 制造404、412、500三种错误来测试
操作步骤
- 安装koa-json-error
- 使用koa-json-error的默认配置处理错误
- 修改配置使其在生产环境下禁用错误堆栈的返回
npm i koa-json-error --save
操作步骤
- 安装koa一parameter
- 使用koa一parameter校验参数
- 制造422错误来测试校验结果
npm i koa-parameter --save
本章主要讲解 NoSQL 概念以及 MongoDB 数据库的理论与入门实践。通过 MongoDB Atlas 云数据库学习 MongoDB 的增删改查等常见操作。
- 什么是NoSQL
- 对不同于传统的关系型数据库的数据库管理系统的统称
- NoSQL数据库的分类
- 列存储(HBase)
- 文档存储(MongoDB)
- Key-value存储(Redis)
- 图存储(FlockDB)
- 对象存储(db4o)
- XML存储(BaseX)
- 为什么要用NoSQL
- 简单(没有原子性、一致性、隔离性等复杂规范)
- 便于横向拓展
- 适合超大规模数据的存储
- 很灵活地存储复杂结构的数据(Schema Free)
- 什么是MongoDB ?
- 来自于英文单词"Humongous”, 中文含义为"庞大”
- 面向文档存储的开源数据库
- 由C++编写而成
- 为什么要用MongoDB ?
- 性能好(内存计算)
- 大规模数据存储(可拓展性)
- 可靠安全(本地复制、自动故障转移)
- 方便存储复杂数据结构(Schema Free)
操作步骤
- 注册用户
- 创建集群
- 添加数据库用户
- 设置IP地址白名单
- 获取连接地址
如果连接mongodb过程中出现以下错误,可以尝试设置付款方式/检查用户名&数据库名是否正确更改/等等再试
Error: querySrv ESERVFAIL _mongodb._tcp.vincentebase.yqjup.mongodb.net
at QueryReqWrap.onresolve [as oncomplete] (dns.js:203:19) {
errno: 'ESERVFAIL',
code: 'ESERVFAIL',
syscall: 'querySrv',
hostname: '_mongodb._tcp.vincentebase.yqjup.mongodb.net'
}
Error: queryTxt ESERVFAIL vincentebase.yqjup.mongodb.net
at QueryReqWrap.onresolve [as oncomplete] (dns.js:203:19) {
errno: 'ESERVFAIL',
code: 'ESERVFAIL',
syscall: 'queryTxt',
hostname: 'vincentebase.yqjup.mongodb.net'
}
stackoverflow上的回答
操作步骤
- 安装 Mong oose
- 用 Mongoose 连接 MongoDB
npm i mongoose --save
操作步骤
- 分析用户模块的属性
- 编写用户模块的Schema
- 使用Schema生成用户Model
操作步骤
- 用Mongoose实现增删改查接口
- 用Postman测试增删改查接口
本章主要讲解 JWT 如何实现用户的认证与授权。从 Session 开始讲解过渡到 JWT,关键在于 Session 和 JWT 的对比。以及通过 Koa 框架的 JWT 中间件实现用户注册于授权登录功能。
- Session的优势
- 相比JWT,最大的优势就在于可以主动清除session了
- session保存在服务器端,相对较为安全
- 结合cookie使用,较为灵活,兼容性较好
- Session的劣势
- cookie + session在跨域场景表现并不好
- 如果是分布式部署,需要做多机共享session机制
- 基于cookie的机制很容易被CSRF
- 查询session信息可能会有数据库查询操作
- Session相关的概念介绍
- session: 主要存放在服务器端,相对安全
- cookie: 主要存放在客户端,并且不是很安全
- sessionStorage: 仅在当前会话下有效,关闭页面或浏览器后被清除
- localstorage: 除非被清除,否则永久保存
- JSON Web Token是一个开放标准(RFC 7519)
- 定义了一种紧凑且独立的方式,可以将各方之间的信息作为JSON对象进行安全传输
- 该信息可以验证和信任,因为是经过数字签名的
- 头部(Header)
- typ: token的类型, 这里固定为JWT
- alg: 使用的hash算法,例如:HMACSHA256或者RSA
- 编码前: {"alg":"HS256","typ":"JWT"}
- Base64编码: 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9'
- 有效载荷(Payload)
- 存储需要传递的信息,如用户ID、用户名等
- 还包含元数据,如过期时间、发布人等
- 与Header不同,Payload可以加密
- 编码前: {"user_id":"zhangsan"}
- Base64编码: 'eyJ1c2VyX2lkIjoiemhhbmdzYW4ifQ=='
- Base64Url编码: 'eyJ1c2VyX2lkIjoiemhhbmdzYW4ifQ'
- 签名(Signature)
- 对Header和Payload部分进行签名
- 保证Token在传输的过程中没有被篡改或者损坏
- Signature = HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload), secret)
JWT | Session | |
---|---|---|
可拓展性 | 无缝水平拓展 | 适合垂直拓展 |
安全性 | JS可修改JWT,签名+加密 | |
RESTful API | 无状态 | 有状态 |
性能 | 传输信息多,请求开销大 | 需要查找用户信息,服务器开销大 |
时效性 | 只有到期才可销毁 | 可以在服务器端更新 |
操作步骤
- 安装 jsonwebtoken
- 签名
- 验证
npm i jsonwebtoken
node
> jwt = require('jsonwebtoken');
> token = jwt.sign({name: 'vincente'}, 'secret');
> jwt.decode(token);
> jwt.verify(token, 'secret');
操作步骤
- 设计用户Schema
- 编写保证唯一性的逻辑
操作步骤
- 登录接口设计
- 用jsonwebtoken生成token
操作步骤
- 认证:验证token ,并获取用户信息
- 授权:使用中间件保护接口
操作步骤
- 安装 koa-jwt
- 使用中间件保护接口
- 使用中间件获取用户信息
npm i koa-jwt --save