Node.js的中间件机制是服务端框架处理请求的核心设计,它允许开发者将请求处理流程拆分成多个独立的函数,每个函数完成特定的功能,最终串联起来完成完整的请求响应处理。这种机制让代码复用性更高,逻辑拆分更清晰,是Express、Koa等主流Node.js框架的基础能力。

什么是Node.js中间件
中间件本质上是一个函数,它接收三个核心参数:请求对象req、响应对象res、以及下一个中间件执行函数next。在Express框架中,一个典型的中间件函数结构如下:
// Express中间件示例
function middleware(req, res, next) {
// 执行自定义逻辑,比如记录请求日志
console.log(`${req.method} ${req.url}`);
// 调用next执行下一个中间件
next();
}
中间件的执行顺序是按照添加的顺序依次执行,上一个中间件调用next之后,才会执行下一个中间件。如果某个中间件没有调用next,那么后续的中间件都不会执行,请求会停留在这个中间件的处理逻辑中。
中间件的核心特性
- 顺序执行:中间件按照添加的顺序依次执行,先添加的中间件先执行。
- 共享上下文:所有中间件共享同一个
req和res对象,可以在中间件中给req或res挂载自定义属性,后续中间件可以直接使用。 - 可终止流程:如果中间件直接返回响应(比如调用
res.end),不再调用next,那么整个请求处理流程就会终止。 - 支持异步:中间件内部可以执行异步操作,异步操作完成后再调用
next即可,不过需要注意异步错误捕获的处理。
手动实现基础中间件系统
接下来我们手动实现一个简易的中间件容器,模拟Express的中间件核心逻辑,支持添加中间件和执行中间件队列。
第一步:定义中间件容器类
首先创建一个MiddlewareManager类,用来存储和管理所有添加的中间件:
class MiddlewareManager {
constructor() {
// 存储所有中间件的数组
this.middlewares = [];
}
// 添加中间件的方法
use(middleware) {
if (typeof middleware !== 'function') {
throw new Error('中间件必须是函数类型');
}
this.middlewares.push(middleware);
// 返回this支持链式调用
return this;
}
}
第二步:实现中间件执行逻辑
我们需要一个方法,用来依次执行所有中间件,并且处理next的调用逻辑。这里使用递归的方式实现中间件的顺序执行:
class MiddlewareManager {
constructor() {
this.middlewares = [];
}
use(middleware) {
if (typeof middleware !== 'function') {
throw new Error('中间件必须是函数类型');
}
this.middlewares.push(middleware);
return this;
}
// 执行所有中间件,接收req和res作为参数
run(req, res) {
// 当前执行到中间件的索引
let index = 0;
// 定义next函数,用来执行下一个中间件
const next = () => {
// 如果所有中间件都执行完了,直接返回
if (index >= this.middlewares.length) {
return;
}
// 取出当前要执行的中间件
const currentMiddleware = this.middlewares[index];
index++;
try {
// 执行当前中间件,传入req、res、next
// 这里判断中间件返回的是不是Promise,处理异步情况
const result = currentMiddleware(req, res, next);
if (result && typeof result.then === 'function') {
// 如果是异步中间件,等待Promise完成再继续(这里简化错误处理,实际可以加catch)
result.catch(err => {
console.error('异步中间件执行出错:', err);
});
}
} catch (err) {
console.error('中间件执行出错:', err);
}
};
// 启动第一个中间件的执行
next();
}
}
第三步:结合HTTP服务器测试
我们把实现的中间件系统和Node.js原生的http模块结合,创建一个简单的HTTP服务器,测试中间件的执行效果:
const http = require('http');
// 创建中间件管理器实例
const middlewareManager = new MiddlewareManager();
// 添加第一个中间件:记录请求日志
middlewareManager.use((req, res, next) => {
console.log(`收到请求: ${req.method} ${req.url}`);
// 给req挂载自定义属性
req.requestTime = new Date().toLocaleString();
next();
});
// 添加第二个中间件:处理请求路径
middlewareManager.use((req, res, next) => {
if (req.url === '/hello') {
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end(`你好,请求时间是: ${req.requestTime}`);
// 这里没有调用next,流程终止
} else {
next();
}
});
// 添加第三个中间件:处理404情况
middlewareManager.use((req, res) => {
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('页面不存在');
});
// 创建HTTP服务器
const server = http.createServer((req, res) => {
// 执行中间件队列
middlewareManager.run(req, res);
});
// 启动服务器,监听3000端口
server.listen(3000, () => {
console.log('服务器运行在 http://127.0.0.1:3000');
});
测试效果说明
启动上面的代码后,用浏览器访问http://127.0.0.1:3000/hello,会看到返回你好和请求时间的内容,同时控制台会打印请求日志。如果访问其他路径比如http://127.0.0.1:3000/test,会返回页面不存在的响应,说明第三个中间件生效了。
常见注意事项
- 中间件中如果没有调用
next,也没有返回响应,请求会一直处于 pending 状态,直到超时。 - 异步中间件如果抛出错误,需要在中间件内部或者
next的调用逻辑中做好错误捕获,避免程序崩溃。 - 不要在一个中间件中多次调用
next,否则会导致后续中间件被重复执行,出现逻辑错误。
中间件机制的核心就是维护一个中间件队列,通过next函数控制队列的执行顺序,理解了这个逻辑,就能轻松掌握Express、Koa等框架的中间件原理,也可以根据需求自定义更复杂的中间件系统。
Node.js中间件Expressmiddlewarehttp_server修改时间:2026-06-23 20:24:38