Koa
友情链接 https://jspang.com/detailed?i...
- npm init -y
- npm i koa2 --S
- package.json 配置启动脚本 "start": "node app.js"
- npm i nodemon -g "start": "nodemon app.js"
- 没有webpeck 翻译请不要使用import
优点
使用 koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的回调函数嵌套,并极大地提升错误处理的效率。一个Koa应用就是一个对象,包含了一个middleware数组,这个数组由一组Generator函数组成。这些函数负责对HTTP请求进行各种加工,比如生成缓存、指定代理、请求重定向等等。这些中间件函数基于 request 请求以一个类似于栈的结构组成并依次执行。
升级Node版本方法
Koa2的开发,Node.js是有要求的,它要求Node.js版本高于V7.6。因为node.js 7.6版本开始完全支持async/await,如果你的版本过低,还是windows系统,我告诉你一个最暴力的方法,直接下载新的安装包,重新安装,覆盖原来的安装位置。
1 使用
- 导入koa
- 实例化app对象
- 编写中间件 async
- 将中间件添加至应用 app.use 返回this 也就是app本身
- 启动服务启动监听
- 使用postman 或者 浏览器访问
// 一. 导入koa const Koa = require('koa') // 二. 实例化对象 const app = new Koa() // 三. 编写中间件 app.use((ctx) => { /*ctx context http 请求的上下文 ctx.body === ctx.response.body ctx.request:是Koa2中context经过封装的请求对象,它用起来更直观和简单。 tx.req:是context提供的node.js原生HTTP请求对象。这个虽然不那么直观,但是可以得到更多的内容,适合我们深度编程。 */ ctx.body = 'hello Koa2' }) // 四. 启动服务 app.listen(3000, () => { console.log('server is running on http://localhost:3000') })
注意
如果没有通过
ctx.body
返回给客户端, 最终会得到Not Found
2 洋葱模型
与express 不同 express是所有中间件顺序执行结束后响应.koa遇见next后会跳出当前中间件,执行下一个中间件,直到没有next 然后回到上一个中间件执行next之后的代码,直到第一个。所以在use中, 一次只能接受一个函数做为参数
app.use(async (ctx, next)=> {
console.log(1);
ctx.body='222';
await next();
// 想输出1 必须等待上面的next结束 记得画图
console.log(1);
})
.use(async (ctx, next)=> {
console.log(2);
await next()
console.log(2);
})
.use(async (ctx, next)=> {
console.log(3);
await next()
console.log(3);
})
//输出 1 2 3 2 1
2.1 异步处理
如果中间件中存在一些异步的代码, Koa也提供了统一的处理方式. 首先, 我们要了解async await语法
1) async await语法
async: 声明异步函数
await: 后跟一个promise对象
如果要使用await, 需要在函数声明前加上async
2) 示例
需求
- 在middleware1中, 构造一个message = aa
- 在middleware2中, 同步追加bb
- 在middleware3中, 异步追加cc
最终在middleware1中, 通过body返回数据
2.2 中间件
顾名思义, 中间件就是在什么的中间
在请求和响应中间的处理程序
有时候从请求到响应的业务比较复杂, 将这些复杂的业务拆开成一个个功能独立的函数, 就是中间件
对于处理请求来说,在响应发出之前,可以在请求和响应之间做一些操作,并且可以将这个处理结果传递给下一个函数继续处理
中间件函数,帮助拆解主程序的业务逻辑,
并且每一个的中间件函数处理的结果都会传递给下一个中间件函数。
就好比工厂里流水线工人清洗一个箱子:
第一个人清洗侧面,第二个人清洗底面,第三个人清洗顶面,。。。
这条流水线结束后,箱子也就清洗干净了
各做各的,不相互影响,又彼此协作
3. 路由
1 什么是路由
路由
- 建立URL和处理函数(中间件)之间的对应关系
- 主要作用: 根据不同的Method和URL返回不同的内容
需求
根据不同的Method+URL, 返回不同的内容
要求:
- Get 请求/, 返回'这是主页'
- Get 请求/users, 返回'这是用户页'
Post请求/users, 返回'创建用户'
原生实现// 一. 导入koa const Koa = require('koa') // 二. 实例化对象 const app = new Koa() // 三. 编写中间件 app.use((ctx) => { if (ctx.url == '/') { ctx.body = '这是主页' } else if (ctx.url == '/users') { if (ctx.method == 'GET') { ctx.body = '这是用户列表页' } else if (ctx.method == 'POST') { ctx.body = '创建用户' } else { ctx.status = 405 // 不支持的请求方法 } } else { ctx.status = 404 } }) // 四. 启动服务 app.listen(3000, () => { console.log('server is running on http://localhost:3000') })
原生书写代码的可维护性差,业务复杂,原生也不够友好。由此出现路由中间件
路由中间件 npm i koa-router
提供了405 501状态 router.allowedMethods通过它来实现
4** 客户端错误 请求方式不支持
5** 服务器错误 服务器没有这种请求方式
在koa的基础上
1. 导入`koa-router`包
2. 实例化router对象
3. 使用router处理路由
4. 注册中间件
// app 入口文件
const Koa = require('koa2');
const Router = require('koa-router');
// 声明应用
const app = new Koa();
const router = new Router();
router.get('/', async ctx => {
ctx.body = 'router'
})
// 注册中间件 router.routes()启动路由 router.allowedMethods()允许任意请求
app.use(router.routes(), router.allowedMethods())
.listen (9000,()=>{
console.log('serve start.....111');
})
路由重定向
路由入口文件中书写
router.redirect('/', '/home') 参数1 用户输入的 参数2是重定向的
路由前缀
比如在user.route.js中
定义路由对象时传入参数
const router = new Router({ prefix: '/users' });
对于router.get('/') == > 实际就是/users
子路由
路由入口文件中书写
router.use ('/list', 第一层子路由list.routes(),list.allowedMethods())
404无效路由
错误处理
项目拆解
app.js 是入口文件,里面不要写路由的东西。创建一个路由文件夹,但是路由文件也需要拆分,index.js是路由的入口,只做重定向,其他的路由定义不同的js文件
4 参数解析
1 为什么
在很多场景中, 后端都需要解析请求的参数, 作为数据库操作的条件。
场景一
前端希望通过请求, 获取id=1的用户信息
接口设计
GET /users/:id
解决
在GET请求中, 有些参数可以通过路由传参, 可以通过params
得到
// GET /users/:id ---- 根据id获取单个用户的信息, 返回一个对象
router.get('/:id', (ctx) => {
// 解析id参数
const id = ctx.params.id
const res = db.filter((item) => item.id == id)
if (!res[0]) ctx.throw(404)
ctx.body = res[0]
})
场景二
前端希望查询年龄在18到20的用户信息
解决
在GET请求中, 如果以键值对的形式传参, 可以通过query
得到
// GET /users?start=18&end=20 ---- 获取所有的用户信息, 返回一个数组
router.get('/', (ctx) => {
// 通过 ctx.query 是ctx.request.query的代理 解析键值对参数
const { start = 0, end = 0 } = ctx.query
const res = db.filter((item) => item.age >= start && item.age <= end)
// 解析键值对
res.length == 0 ? ctx.throw(404) : (ctx.body = res)
})
场景三
前端注册, 填写了用户名, 年龄, 传递给后端, 后端需要解析这些数据, 保存到数据库
接口设计
解决
Koa不支持body参数解析, 通常借助社区的中间件实现. 官方推荐的有
- koa-bodyparser
- koa-body
1) 安装koa-body
npm install koa-body
2) 注册
// 注册KoaBody中间件, 解析请求体中的参数, 挂载到ctx.request.body
const KoaBody = require('koa-body')
app.use(KoaBody())
3) 使用
通过ctx.request.body
获取请求体中的数据
小结
对于不同的Http请求, 需要使用不同的方式携带参数
- GET请求: 在URL中以键值对传递
- POST/PUT/PATCH/DELET请求: 在请求体中传递
五. 错误处理
对于接口编程, 错误处理是非常重要的环节, 通过提供更友好的提示
- 提高错误定位的效率
- 提高代码的稳定性和可靠性
1 原生的错误处理
一般Koa中的错误分为三类
- 404: 当请求的资源找不到, 或者没有通过
ctx.body
返回时, 由koa自动返回 - 手动抛出: 通过
ctx.throw
手动抛出 - 500: 运行时错误
Koa类是继承Emitter类, 因此可以
- 通过emit提交一个错误
- 通过on进行统一错误处理
app.on('error', (err, ctx) => {
console.error(err)
ctx.body = err
})
只能捕捉ctx.app.emit的错误
2 使用中间件
1) 安装
npm i koa-json-error
2) 使用
基本使用
const error = require('koa-json-error')
app.use(error())
高级使用
const error = require('koa-json-error')
app.use(
error({
format: (err) => {
return { code: err.status, message: err.message, result: err.stack }
},
postFormat: (err, obj) => {
const { result, ...rest } = obj
return process.env.NODE_ENV == 'production' ? rest : obj
},
})
)
vscode 调试node 代码
node Launch Program
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。