为koa移植express中间件
前言
在前面的对
vue-ssr
改造为koa
的web
框架,我使用了一个第三方npm库。包名为
已迁移到koa2-webpack-middleware-zm
koa-webpack-middleware-zm
。这个包是我自己因为ssr的特殊需求
github
上并没有合适的包。所以自行参考了koa-webpack-middleware后写出的包。
并且修复原有包的一些 bug。
这篇博文我将写以下内容
koa 中间件的编写。
把
webpack-dev-middleware
这种express
中间件改造为一个koa
中间件。
一. koa与express的普通中间件区别。
npm 包安装
npm i koa express -D
koa和express的基本模板。
koa只能用new的方式创建
// 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
来通知跳转到下一个中间件。
三. 修改一个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
结束,
修改next
用reject
替代通知Promise
调用next
。
四. 修改express注意事项
原有的
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()
才能跳转到下一个组件。
五. 改造webpack-dev-middleware的例子
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的例子
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
自动集成测试.