【注意】最后更新于 June 15, 2020,文中内容可能已过时,请谨慎使用。
前言
- 在前面的对
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 的普通中间件区别。
- koa 和 express 的基本模板。
koa 只能用 new 的方式创建
1
2
3
4
5
| // koa
const Koa = require("koa");
// ... use code
const KoaApp = new Koa();
KoaApp.listen(8000);
|
express 可以用方法调用或 new 的方式创建
1
2
3
4
5
| // express
const Express = require("express");
// ... use code
const ExpressApp = Express();
ExpressApp.listen(8080);
|
1
2
3
4
| // use code
KoaApp.use(function(ctx, next) {
ctx.body = "hello koa";
});
|
express:
1
2
3
4
| // use code
ExpressApp.use(function(req, res, next) {
res.end("hello exress");
});
|
- 中间件为一个方法接受 req,res,next 三个参数。
- 中间可以执行任何方法包括异步方法。
- 最后一定要通过
res.end
或者next
来通知结束这个中间件方法。 - 如果没有执行
res.end
或者next
访问会一直卡着不动直到超时。 - 并且在这之后的中间件也会没法执行到。
- 中间件为一个方法或者其它,这里就讲方法的,接受
ctx,next
两个参数。 - 方法中可以执行任何同步方法。可以使用返回一个
Promise
来做异步。 - 中间件通过方法结束时的返回来判断是否进入下一个中间件。
- 返回一个
Promise
对象 koa 会等待异步通知完成。then 中可以返回 next()来跳转到下一个中间件。 - 相同如果
Promise
没有异步通知也会卡住。
二. 异步中间件的区别
1
2
3
4
5
| ExpressApp.use(function(req, res, next) {
setTimeout(function() {
res.end("测试");
}, 0);
});
|
express 的异步就是最普通的回调
1
2
3
4
5
6
7
8
9
10
| 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
1
2
3
4
5
6
7
8
9
| module.exports = function(req, res, next) {
setTimeout(function() {
if (req.path === "/") {
res.end("测试");
} else {
next();
}
}, 0);
};
|
1
2
| const test = require("./hello-test.js");
ExpressApp.use(test);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| 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
对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
| 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 的例子
devMiddleware.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| 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
1
2
3
4
5
6
7
8
| function koaHotMiddleware(expressHotMiddleware) {
return function middleware(ctx, next) {
return new Promise(resolve => {
expressHotMiddleware(ctx.req, ctx.res, resolve);
}).then(next);
};
}
module.exports = koaHotMiddleware;
|
七. 例子源码
- koa-webpack-middleware-zm
- 欢迎 star,issues,fork, pr
- 下篇写这些内容
- 在
npm
上发布你的包以共享给其他人使用。 - 添加测试用例
- 添加
travis-ci
自动集成测试.
文章作者
上次更新
2020-06-15 18:12:42 +08:00
(9c054d8)
许可协议
CC BY-NC-ND 4.0