js 实现middleware
中间件(Middleware)概念
中间件是一种在请求和响应之间执行特定功能的机制,常用于处理请求前后的逻辑(如日志、鉴权、数据转换)。在JavaScript中,中间件广泛应用于Express、Koa等框架。
实现基础中间件模式
以下是一个简单的中间件实现示例,模拟类似Express的中间件机制:
function createMiddleware() {
const middlewareStack = [];
const use = (fn) => {
middlewareStack.push(fn);
};
const run = (context) => {
let index = 0;
const next = () => {
if (index < middlewareStack.length) {
const currentFn = middlewareStack[index++];
return currentFn(context, next);
}
};
next();
};
return { use, run };
}
使用示例:
const app = createMiddleware();
app.use((ctx, next) => {
console.log('Middleware 1 - Start');
next();
console.log('Middleware 1 - End');
});
app.use((ctx, next) => {
console.log('Middleware 2 - Start');
next();
console.log('Middleware 2 - End');
});
app.run({}); // 执行中间件栈
异步中间件支持
通过async/await支持异步操作:
function createAsyncMiddleware() {
const middlewareStack = [];
const use = (fn) => {
middlewareStack.push(fn);
};
const run = async (context) => {
let index = 0;
const next = async () => {
if (index < middlewareStack.length) {
const currentFn = middlewareStack[index++];
await currentFn(context, next);
}
};
await next();
};
return { use, run };
}
使用示例:
const app = createAsyncMiddleware();
app.use(async (ctx, next) => {
console.log('Async Middleware 1 - Start');
await new Promise(resolve => setTimeout(resolve, 1000));
await next();
console.log('Async Middleware 1 - End');
});
app.run({});
洋葱圈模型实现
Koa风格的洋葱圈模型(中间件双向执行):
function createOnionMiddleware() {
const middlewareStack = [];
const use = (fn) => {
middlewareStack.push(fn);
};
const compose = (context) => {
let index = -1;
const dispatch = (i) => {
if (i <= index) throw new Error('next() called multiple times');
index = i;
const fn = middlewareStack[i] || (() => {});
return fn(context, dispatch.bind(null, i + 1));
};
return dispatch(0);
};
return { use, run: compose };
}
执行顺序说明:
- 中间件按注册顺序执行
next()前的代码。 - 遇到
next()会暂停当前中间件,执行下一个中间件。 - 最后一个中间件执行完毕后,逆序执行剩余代码。
实际应用场景
- 日志记录:在请求前后记录时间戳和参数。
- 权限校验:拦截未授权的请求。
- 数据预处理:对请求体进行格式化或验证。
示例:权限校验中间件

app.use((ctx, next) => {
if (!ctx.headers.token) {
throw new Error('Unauthorized');
}
next();
});
注意事项
- 避免在中间件中阻塞主线程(长时间同步操作)。
- 错误处理需通过
try/catch或顶层错误事件捕获。 - 中间件的顺序会影响执行逻辑,需谨慎设计。
通过以上模式,可灵活扩展中间件功能,适应不同场景需求。






