Koa2的几个特点:
- 中间件只有use方法进行中间件注册
- 中间件的返回值是promise实例
- 中间件的入参中有ctx上下文,ctx包含req,res,cookie等;入参第二个参数next实现链式调用
- 执行中间件时,执行的过程符合洋葱模型(先开始执行的中间件,执行的结果后打印出来,具体可看后面的中间件调用的例子)
下面是like-koa2.js的实现
function compose(middlewares) {
return (ctx) => {
// 传入ctx,返回promise;把middleware中的中间件都执行完
function dispatch(i) {
const fn = middlewares[i]
try {
return Promise.resolve(fn(ctx, dispatch.bind(null, i + 1)))
} catch (error) {
return Promise.reject(error)
}
}
return dispatch(0)
}
}
const http = require('http')
class KoaTest3 {
constructor() {
this.middleWares = []
}
use() {
const argLists = [...arguments]
this.middleWares.push(...argLists)
}
getCtx(req, res) {
const ctx = {}
ctx.req = req
ctx.res = res
return ctx
}
callback() {
return (req, res) => {
res.setHeader("Content-type", "application/json");
// ctx是所有中间件共用
const ctx = this.getCtx(req, res)
// 依次执行每一个中间件
// 中间件的入参是ctx 和 指向middleWares的index,返回值是Promise实例, 且依次往后调用
const fn = compose(this.middleWares)
return fn(ctx)
}
}
listen() {
const server = http.createServer(this.callback())
server.listen(...arguments)
}
}
module.exports = KoaTest3
在test.js中调用like-koa2.js
const Koa = require('./like-koa2.js')
const app = new Koa()
app.use(async (ctx, next) => {
console.log(1);
await next()
console.log(2);
const rt = ctx['X-Response-Time']
console.log(`${ctx.req.method} ${ctx.req.url} - ** ${rt}`)
})
// x-response-time
app.use(async(ctx, next) => {
const start = Date.now()
console.log(3);
await next()
console.log(4);
const ms = Date.now() - start
ctx['X-Response-Time'] = `${ms} ms`
})
app.use(async ctx => {
const url = ctx.req.url
const method = ctx.req.method.toLowerCase()
if(url === '/api/user/update' && method === 'post') {
ctx.res.end(JSON.stringify({
errno: 0,
data: {name: 'zhangsan', id: 1}
}))
}else if(url === '/api/blog/list') {
ctx.res.end(JSON.stringify({
errno: 0,
data: {title: 'blog title', id: 1, time: '2022-2-13 22:06:40'}
}))
} else {
ctx.res.end(JSON.stringify({errno: 0, value: 'we11'}))
}
})
app.listen(8989, () => {
console.log('welcome, 8989!!')
})
执行node test.js,访问 http://localhost:8989/api/blog/list 控制台打印的结果:
1
3
4
2
GET /api/blog/list - ** 5 ms
接口返回的结果:
{"errno":0,"data":{"title":"blog title","id":1,"time":"2022-2-13 22:06:40"}}
以上,就是koa2的中间件注册和使用。难点是compose 方法的实现。