Koa2經過app.use(function)方法來註冊中間件。
全部的http請求都會依次調用app.use()方法,因此中間件的使用順序很是重要。javascript
官方說明:java
假設依次有 A、B 兩個中間件,首先請求流經過 A 中間件,而後繼續移交控制給 B 中間件。當一箇中間件調用 next() 則該函數暫停並將控制傳遞給定義的下一個中間件。當在下游沒有更多的中間件執行後,堆棧將展開而且每一箇中間件恢復執行其上游行爲。node
咱們來作個簡單的測試,寫三個中間件來測試執行順序:json
const Koa = require('koa') const app = new Koa() app.use(async (ctx, next) => { console.log('http request 1') await next() console.log('http request end 1') }) app.use(async (ctx, next) => { console.log('http request 2') await next() console.log('http request end 2') }) app.use(async (ctx, next) => { console.log('http request 3') await next() console.log('http request end 3') }) app.listen(8000) module.exports = app
模擬了一個請求以後,能夠看到node.js控制檯依次輸出:瀏覽器
http request 1 http request 2 http request 3 http request end 3 http request end 2 http request end 1
所以,能夠得知官網的意思是:中間件中的方法,會以一個棧結構的順序來執行,先由上至下依次執行,在遇到await next()方法後,會暫停該中間件的執行,執行下一個中間件,當全部的中間件都執行完畢時,再由下往上依次執行每一箇中間件next 後面的方法。bash
知道了中間件的執行原理,寫一箇中間件就很是簡單了。
例如實現一個簡單的打印請求耗時的中間件只須要簡單的幾行代碼:app
app.use(async (ctx, next) => { const url = ctx.url const method = ctx.method console.time(`-- ${method} ${url} cost`) await next() console.timeEnd(`-- ${method} ${url} cost`) })
在瀏覽器發起一個請求localhost:8000?username=zj。
在node.js控制檯打印:koa
-- GET /?username=zj cost: 2.337ms -- GET /favicon.ico cost: 0.159ms
能夠看到第一個是正常請求的log,第二個是請求圖標的log。curl
koa-bodyparser
中間件可以幫咱們自動解析post參數。
經過koa-bodyparser
,咱們可以很方便的在ctx.request.body裏面直接獲取到解析好的數據。
請看代碼:async
const Koa = require('koa') const app = new Koa() const bodyparser = require('koa-bodyparser') app.use(bodyparser({ enableTypes:['json', 'form', 'text'] })) app.use(async ctx => { const req = ctx.request const url = req.url // 請求的url const method = req.method // 請求的方法 console.log(req.body) ctx.body = req.body }) app.listen(8000) module.exports = app
經過curl模擬請求:
$ curl -i -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"id":100}' http://localhost:8000
能夠看到node.js控制檯輸出:
{ id: 100 }
koa-router
是一款官方默認的路由中間件,若是咱們本身實現路由的話,可能須要手動去判斷請求url,再返回不一樣的響應,可是有了koa-router
中間件以後,咱們能夠很方便的對路由進行系統化的管理。 具體使用方法咱們在下節再講。