在前面的對vue-ssr
改造爲koa
的web
框架,我使用了一個第三方npm庫。javascript
包名爲 已遷移到koa2-webpack-middleware-zm
koa-webpack-middleware-zm
。vue
這個包是我本身由於ssr的特殊需求github
上並無合適的包。java
因此自行參考了koa-webpack-middleware後寫出的包。webpack
而且修復原有包的一些 bug。git
這篇博文我將寫如下內容github
koa 中間件的編寫。web
把
webpack-dev-middleware
這種express
中間件改造爲一個koa
中間件。shell
npm 包安裝express
npm i koa express -D
koa和express的基本模板。
koa只能用new的方式建立npm
// koa const Koa = require('koa') // ... use code const KoaApp = new Koa() KoaApp.listen(8000)
express能夠用方法調用或new的方式建立
// express const Express = require('express') // ... use code const ExpressApp = Express() ExpressApp.listen(8080)
二者的hello。
koa:
// use code KoaApp.use(function(ctx, next){ ctx.body = 'hello koa' })
express:
// use code ExpressApp.use(function(req, res, next){ res.end('hello exress') })
express 中間件運行邏輯
中間件爲一個方法接受 req,res,next 三個參數。
中間能夠執行任何方法包括異步方法。
最後必定要經過
res.end
或者next
來通知結束這個中間件方法。若是沒有執行
res.end
或者next
訪問會一直卡着不動直到超時。而且在這以後的中間件也會無法執行到。
koa 的中間件運行邏輯
中間件爲一個方法或者其它,這裏就講方法的,接受
ctx,next
兩個參數。方法中能夠執行任何同步方法。可使用返回一個
Promise
來作異步。中間件經過方法結束時的返回來判斷是否進入下一個中間件。
返回一個
Promise
對象koa會等待異步通知完成。then中能夠返回next()來跳轉到下一個中間件。相同若是
Promise
沒有異步通知也會卡住。
express 異步中間件
ExpressApp.use(function(req, res, next){ setTimeout(function(){ res.end('測試') }, 0) })
express 的異步就是最普通的回調
koa 異步中間件
KoaApp.use(function(ctx, next){ return new Promise(function(resolve, reject) { if (ctx.path === '/'){ ctx.body = 'hello koa' resolve() } else { reject() } }).catch(next) })
koa 的異步經過Promise
來作這裏我then
不寫表明resolve
不切換到下一個中間件。catch
直接綁定next
,用reject
來通知跳轉到下一個中間件。
hello-test.js
module.exports = function(req, res, next){ setTimeout(function(){ if (req.path === '/'){ res.end('測試') }else{ next() } }, 0) }
express 使用
const test = require('./hello-test.js') ExpressApp.use(test)
修改到 koa 使用
const test = require('./hello-test.js') KoaApp.use(function (ctx, next){ const res = ctx.res const req = ctx.req const end = res.end return new Promise(function(resolve, reject) { res.end = function () { end.apply(this, arguments) resolve() } test(res, req, reject) }).catch(next) })
經過修改原有的res.end
運行resolve
通知Promise
結束,
修改next
用reject
替代通知Promise
調用next
。
原有的express
組件是經過回調來通知結束的。不要直接await
或者yield
一個組件。它們又不是返回一個Promise
對象。
const test = require('./hello-test.js') KoaApp.use(function *(next){ const res = this.res const req = this.req // 這種寫法會致使後面註冊的中間件都失效。 yield test(res, req, next) }) KoaApp.use(async function (ctx, next){ const res = ctx.res const req = ctx.req // 這種寫法會致使後面註冊的中間件都失效。 await test(res, req, next) })
只有在catch
或者是then
中返回next()
才能跳轉到下一個組件。
function koaDevMiddleware(expressDevMiddleware) { return function middleware(ctx, next) { return new Promise((resolve) => { expressDevMiddleware(ctx.req, { end: (content) => { ctx.body = content; resolve(false); }, setHeader: (name, value) => { ctx.set(name, value); }, }, () => { resolve(true); }); }).then((err) => { if (err) { return next(); } return null; }); }; } module.exports = koaDevMiddleware;
這是昨天最新的代碼當時沒想着用reject
來通知next
後面大概要改爲這樣。
function koaHotMiddleware(expressHotMiddleware) { return function middleware(ctx, next) { return new Promise((resolve) => { expressHotMiddleware(ctx.req, ctx.res, resolve); }).then(next); }; } module.exports = koaHotMiddleware;
歡迎star,issues,fork, pr
下篇博文寫
在
npm
上發佈你的包以共享給其餘人使用。添加測試用例
添加
travis-ci
自動集成測試.