爲koa移植express中間件

前言

  • 在前面的對vue-ssr改造爲koaweb框架,我使用了一個第三方npm庫。javascript

  • 包名爲 koa2-webpack-middleware-zm 已遷移到koa-webpack-middleware-zmvue

  • 這個包是我本身由於ssr的特殊需求github上並無合適的包。java

  • 因此自行參考了koa-webpack-middleware後寫出的包。webpack

  • 而且修復原有包的一些 bug。git

  • 這篇博文我將寫如下內容github

  • koa 中間件的編寫。web

  • webpack-dev-middleware這種express中間件改造爲一個koa中間件。shell

一. koa與express的普通中間件區別。

  • 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 中間件運行邏輯

  1. 中間件爲一個方法接受 req,res,next 三個參數。

  2. 中間能夠執行任何方法包括異步方法。

  3. 最後必定要經過res.end或者next來通知結束這個中間件方法。

  4. 若是沒有執行res.end或者next訪問會一直卡着不動直到超時。

  5. 而且在這以後的中間件也會無法執行到。

  • koa 的中間件運行邏輯

  1. 中間件爲一個方法或者其它,這裏就講方法的,接受ctx,next兩個參數。

  2. 方法中能夠執行任何同步方法。可使用返回一個Promise來作異步。

  3. 中間件經過方法結束時的返回來判斷是否進入下一個中間件。

  4. 返回一個Promise對象koa會等待異步通知完成。then中能夠返回next()來跳轉到下一個中間件。

  5. 相同若是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來通知跳轉到下一個中間件。

三. 修改一個express中間件到koa

  • 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結束,
修改nextreject替代通知Promise調用next

四. 修改express注意事項

  1. 原有的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)
})
  1. 只有在catch或者是then中返回next()才能跳轉到下一個組件。

五. 改造webpack-dev-middleware的例子

devMiddleware.js

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後面大概要改爲這樣。

六. 改造webpack-hot-middleware的例子

hotMiddleware.js

function koaHotMiddleware(expressHotMiddleware) {
    return function middleware(ctx, next) {
        return new Promise((resolve) => {
            expressHotMiddleware(ctx.req, ctx.res, resolve);
        }).then(next);
    };
}
module.exports = koaHotMiddleware;

七. 例子源碼

  1. koa-webpack-middleware-zm

  2. 歡迎star,issues,fork, pr

  3. 原文地址

  4. 下篇博文寫

  • npm上發佈你的包以共享給其餘人使用。

  • 添加測試用例

  • 添加travis-ci自動集成測試.

相關文章
相關標籤/搜索