原创做者:大哼、阿干、三三、小虎、胖子、小哈、DDU、可木、晃晃
文案校对:李益、大力萌、Au、DDU、小溪里、小哈
风采主播:可木、阿干、Au、DDU、小哈
视频剪辑:小溪里
主站运营:给力xi、xty
教程主编:张利涛html
视频地址:https://www.cctalk.com/v/15114357763623webpack
正是由于中间件的扩展性才使得
Koa
的代码简单灵活。
在 app.js
中,有这样一段代码:git
app.use(async (ctx, next)=>{ await next() ctx.response.type = 'text/html' ctx.response.body = '<h1>Hello World</h1>' })
它的做用是:每收到一个 http
请求,Koa
都会调用经过 app.use()
注册的 async
函数,同时为该函数传入 ctx
和 next
两个参数。而这个 async
函数就是咱们所说的中间件。github
下面咱们简单介绍一下传入中间件的两个参数。web
ctx
做为上下文使用,包含了基本的 ctx.request
和 ctx.response
。另外,还对 Koa
内部对一些经常使用的属性或者方法作了代理操做,使得咱们能够直接经过 ctx
获取。好比,ctx.request.url
能够写成 ctx.url
。浏览器
除此以外,Koa
还约定了一个中间件的存储空间 ctx.state
。经过 state
能够存储一些数据,好比用户数据,版本信息等。若是你使用 webpack
打包的话,能够使用中间件,将加载资源的方法做为 ctx.state
的属性传入到 view
层,方便获取资源路径。app
next
参数的做用是将处理的控制权转交给下一个中间件,而 next()
后面的代码,将会在下一个中间件及后面的中间件(若是有的话)执行结束后再执行。koa
注意: 中间件的顺序很重要! async
咱们重写 app.js
来解释下中间件的流转过程:函数
// 按照官方示例 const Koa = require('koa') const app = new Koa() // 记录执行的时间 app.use(async (ctx, next) => { let stime = new Date().getTime() await next() let etime = new Date().getTime() ctx.response.type = 'text/html' ctx.response.body = '<h1>Hello World</h1>' console.log(`请求地址: ${ctx.path},响应时间:${etime - stime}ms`) }); app.use(async (ctx, next) => { console.log('中间件1 doSoming') await next(); console.log('中间件1 end') }) app.use(async (ctx, next) => { console.log('中间件2 doSoming') await next(); console.log('中间件2 end') }) app.use(async (ctx, next) => { console.log('中间件3 doSoming') await next(); console.log('中间件3 end') }) app.listen(3000, () => { console.log('server is running at http://localhost:3000') })
运行起来后,控制台显示:
server is running at http://localhost:3000
而后打开浏览器,访问 http://localhost:3000
,控制台显示内容更新为:
server is running at http://localhost:3000 中间件1 doSoming 中间件2 doSoming 中间件3 doSoming 中间件3 end 中间件2 end 中间件1 end 请求地址: /,响应时间:2ms
从结果上能够看到,流程是一层层的打开,而后一层层的闭合,像是剥洋葱同样 —— 洋葱模型。
此外,若是一个中间件没有调用 await next()
,会怎样呢?答案是『后面的中间件将不会执行』。
修改 app.js
以下,咱们去掉了第三个中间件里面的 await
:
const Koa = require('koa') const app = new Koa() // 记录执行的时间 app.use(async (ctx, next)=>{ let stime = new Date().getTime() await next() let etime = new Date().getTime() ctx.response.type = 'text/html' ctx.response.body = '<h1>Hello World</h1>' console.log(`请求地址: ${ctx.path},响应时间:${etime - stime}ms`) }); app.use(async (ctx, next) => { console.log('中间件1 doSoming') await next(); console.log('中间件1 end') }) app.use(async (ctx, next) => { console.log('中间件2 doSoming') // 注意,这里咱们删掉了 next // await next() console.log('中间件2 end') }) app.use(async (ctx, next) => { console.log('中间件3 doSoming') await next(); console.log('中间件3 end') }) app.listen(3000, () => { console.log('server is running at http://localhost:3000') })
从新运行代码后,控制台显示以下:
server is running at http://localhost:3000 中间件1 doSoming 中间件2 doSoming 中间件2 end 中间件1 end 请求地址: /,响应时间:1ms
与咱们的预期结果『后面的中间件将不会执行』是一致的。
下一篇:咱们将学习下如何响应浏览器的各类请求。
上一篇:iKcamp新课程推出啦~~~~~ iKcamp团队制做|基于Koa2搭建Node.js实战(含视频)☞ 环境准备