前言
用过Express.js
和Koa.js
的人会发现使用方式很类似,也是基于中间件
的理念去实现Web服务。
直接以Express.js
回调式的中间件服务比较容易理解。再基于回调式的中间件服务接入Koa.js
的中间件引擎去处理回调嵌套的处理。
这一章主要以原生的Node.js实现纯回调的中间件HTTP服务。
必要条件
https://github.com/chenshenhai/koajs-design-note/tree/master/demo/chapter-01-06
服务类封装
const http = require('http');
const Emitter = require('events');
class WebServer extends Emitter {
constructor() {
super();
this.middleware = [];
this.context = Object.create({});
}
/**
* 服务事件监听
* @param {*} args
*/
listen(...args) {
const server = http.createServer(this.callback());
return server.listen(...args);
}
/**
* 注册使用中间件
* @param {Function} fn
*/
use(fn) {
if (typeof fn === 'function') {
this.middleware.push(fn);
}
}
/**
* 中间件总回调方法
*/
callback() {
let that = this;
if (this.listeners('error').length === 0) {
this.on('error', this.onerror);
}
const handleRequest = (req, res) => {
let context = that.createContext(req, res);
this.middleware.forEach((cb, idx) => {
try {
cb(context);
} catch (err) {
that.onerror(err);
}
if (idx + 1 >= this.middleware.length) {
if (res && typeof res.end === 'function') {
res.end();
}
}
});
};
return handleRequest;
}
/**
* 异常处理监听
* @param {EndOfStreamError} err
*/
onerror(err) {
console.log(err);
}
/**
* 创建通用上下文
* @param {Object} req
* @param {Object} res
*/
createContext(req, res) {
let context = Object.create(this.context);
context.req = req;
context.res = res;
return context;
}
}
module.exports = WebServer;
服务使用
const WebServer = require('./index');
const app = new WebServer();
const PORT = 3001;
app.use(ctx => {
ctx.res.write('<p>line 1</p>');
});
app.use(ctx => {
ctx.res.write('<p>line 2</p>');
});
app.use(ctx => {
ctx.res.write('<p>line 3</p>');
});
app.listen(PORT, () => {
console.log(`the web server is starting at port ${PORT}`);
});