题目
实现一个支持异步中间件的简易Node.js框架核心
信息
- 类型:问答
- 难度:⭐⭐
考点
中间件机制,异步流程控制,错误处理
快速回答
实现要点:
- 创建
Application类管理中间件队列 - 通过
use()方法注册中间件,支持异步函数 - 实现
handleRequest()方法按顺序执行中间件 - 使用
next()机制控制流程传递 - 添加错误处理中间件支持(函数参数为4个)
原理说明
Node.js框架(如Express/Koa)的核心是中间件管道机制:
- 中间件是按顺序执行的函数,接收请求/响应对象和
next回调 - 每个中间件通过调用
next()将控制权移交下一个中间件 - 异步中间件需返回Promise或使用
async/await - 错误处理中间件有4个参数
(err, req, res, next)
代码实现
class Application {
constructor() {
this.middleware = [];
}
// 注册中间件
use(fn) {
if (typeof fn !== 'function') {
throw new TypeError('Middleware must be a function!');
}
this.middleware.push(fn);
}
// 请求处理入口
handleRequest(req, res) {
const ctx = { req, res };
const dispatch = (i) => {
if (i >= this.middleware.length) return Promise.resolve();
const fn = this.middleware[i];
try {
// 执行中间件并处理异步
return Promise.resolve(fn(ctx, () => dispatch(i + 1)));
} catch (err) {
return Promise.reject(err);
}
};
return dispatch(0).catch(err => {
// 触发错误处理
const errorHandler = this.middleware.find(fn => fn.length === 4);
errorHandler?.(err, ctx.req, ctx.res, () => {});
});
}
}
// 使用示例
const app = new Application();
// 普通中间件
app.use(async (ctx, next) => {
console.log('Middleware 1 start');
await next(); // 移交控制权
console.log('Middleware 1 end');
});
// 错误处理中间件(4个参数)
app.use((err, req, res, next) => {
console.error('Error:', err);
res.statusCode = 500;
res.end('Internal Server Error');
});
// 模拟请求
app.handleRequest({}, { end: () => {} });最佳实践
- 使用
Promise.resolve包装中间件返回值,统一处理同步/异步函数 - 通过
fn.length判断错误处理中间件(参数数量为4) - 创建上下文对象
ctx封装req/res,避免污染原生对象 - 在
next()调用处添加try/catch捕获同步错误
常见错误
- 忘记调用
next()导致请求挂起 - 未正确处理异步错误(需用
Promise.catch) - 多次调用
next()引发重复执行 - 错误处理中间件未放在最后(应作为最终兜底)
扩展知识
- Koa对比:Koa使用
async/await替代回调,通过ctx.onerror集中处理错误 - 性能优化:使用组合函数(compose)减少递归开销
- 洋葱模型:中间件执行顺序类似洋葱,先入后出(请求→响应方向)
- 实际应用:Express的
router和Koa的koa-compose都是该模式的工业级实现