为koa移植express中间件
前言
在前面的对
vue-ssr改造为koa的web框架,我使用了一个第三方npm库。包名为
已迁移到koa2-webpack-middleware-zmkoa-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自动集成测试.