原創做者:大哼、阿幹、三三、小虎、胖子、小哈、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實戰(含視頻)☞ 環境準備