node.js学习笔记:中间件
node.js学习笔记:中间件
- 一、中间件的基本结构
- 二、编写和使用中间件的步骤
- 1. 编写中间件函数
- 2. 注册中间件
- 3. 错误处理中间件
- 三、中间件的核心特性
- 四、常见中间件类型
- 总结
在 Node.js(尤其是 Express 框架)中,中间件(Middleware)是一个函数,它可以访问请求对象(req
)、响应对象(res
)以及应用程序的下一个中间件函数(next
)。中间件的主要作用是:处理请求、修改请求/响应对象、终止请求-响应周期,或调用下一个中间件。
一、中间件的基本结构
一个标准的 Express 中间件函数包含 3 个参数:req
(请求)、res
(响应)、next
(下一个中间件)。如果是错误处理中间件,则有 4 个参数:err
、req
、res
、next
。
基本格式:
// 普通中间件
const myMiddleware = (req, res, next) => {// 1. 处理逻辑(如日志、验证、修改req/res等)// 2. 调用 next() 交给下一个中间件;或用 res.send() 终止请求next(); // 必须调用,否则请求会被挂起
};// 错误处理中间件(多一个 err 参数)
const errorMiddleware = (err, req, res, next) => {// 处理错误res.status(500).send('服务器错误:' + err.message);
};
二、编写和使用中间件的步骤
以 Express 为例,编写中间件并应用到项目中,通常分为 3 步:
1. 编写中间件函数
根据需求实现具体逻辑,例如:
示例 1:日志中间件(记录请求信息)
// 记录请求的方法、URL、时间
const loggerMiddleware = (req, res, next) => {const { method, url } = req;const time = new Date().toLocaleString();console.log(`[${time}] ${method} ${url}`);next(); // 交给下一个中间件
};
示例 2:参数验证中间件(检查请求参数)
// 验证 POST 请求的 body 中是否包含 username
const validateUserMiddleware = (req, res, next) => {if (!req.body.username) {// 参数错误,直接响应,终止请求return res.status(400).send('缺少 username 参数');}next(); // 参数正确,继续下一步
};
示例 3:异步中间件(处理异步操作)
// 模拟异步查询数据库,检查用户是否存在
const checkUserExists = async (req, res, next) => {try {const userId = req.params.id;// 模拟数据库查询const user = await db.findUser(userId); // 假设 db.findUser 是异步函数if (!user) {return res.status(404).send('用户不存在');}// 将查询结果挂载到 req 上,供后续中间件使用req.user = user;next();} catch (err) {// 异步错误需传递给错误处理中间件next(err); // 调用 next(err) 会触发错误处理中间件}
};
2. 注册中间件
通过 app.use()
或路由方法(如 app.get()
)注册中间件,使其生效。
全局中间件(对所有请求生效):
const express = require('express');
const app = express();// 注册日志中间件(所有请求都会经过它)
app.use(loggerMiddleware);// 解析 JSON 请求体的内置中间件(Express 自带)
app.use(express.json());
局部中间件(仅对特定路由生效):
// 仅对 POST /user 生效的验证中间件
app.post('/user', validateUserMiddleware, (req, res) => {res.send(`创建用户:${req.body.username}`);
});// 对 /user/:id 路由生效的异步中间件
app.get('/user/:id', checkUserExists, (req, res) => {// 使用 checkUserExists 中间件挂载的 req.userres.send(`用户信息:${JSON.stringify(req.user)}`);
});
多个中间件串联:
// 多个中间件按顺序执行
app.get('/profile',authMiddleware, // 先验证登录checkRoleMiddleware, // 再检查权限(req, res) => { // 最后处理响应res.send('用户资料');}
);
3. 错误处理中间件
专门处理请求过程中产生的错误(同步/异步错误),必须定义 4 个参数(err, req, res, next
),否则 Express 会将其视为普通中间件。
// 注册错误处理中间件(通常放在所有路由之后)
app.use((err, req, res, next) => {console.error('错误详情:', err.stack);// 区分错误类型,返回不同状态码if (err.type === 'validation') {return res.status(400).send(err.message);}// 未知错误返回 500res.status(500).send('服务器内部错误');
});
触发错误处理中间件:
- 同步错误:直接
throw new Error('错误信息')
- 异步错误:调用
next(err)
(如示例 3 中的next(err)
)
三、中间件的核心特性
-
执行顺序:按注册顺序执行,先注册的中间件先处理请求(类似流水线)。
app.use((req, res, next) => {console.log('中间件 1');next(); }); app.use((req, res, next) => {console.log('中间件 2');next(); }); // 访问任何接口,会先打印 "中间件 1",再打印 "中间件 2"
-
终止请求:如果中间件中调用了
res.send()
、res.json()
等响应方法,请求-响应周期会终止,后续中间件不再执行。app.use((req, res, next) => {res.send('终止请求');next(); // 这行代码不会生效,因为响应已发送 }); app.use((req, res, next) => {console.log('不会执行'); });
-
修改请求/响应对象:中间件可以给
req
或res
添加属性/方法,供后续中间件或路由使用(如示例 3 中的req.user
)。
四、常见中间件类型
- 应用级中间件:通过
app.use()
注册,对所有路由生效。 - 路由级中间件:通过
router.use()
注册,仅对特定路由模块生效。 - 内置中间件:Express 自带的中间件,如
express.json()
(解析 JSON 请求体)、express.static()
(托管静态资源)。 - 第三方中间件:如
cors
(处理跨域)、morgan
(日志)、helmet
(安全头),需通过npm
安装后使用。
总结
编写中间件的核心是:
- 定义一个接收
req, res, next
(或err, req, res, next
)的函数。 - 在函数中实现特定逻辑(日志、验证、异步操作等)。
- 调用
next()
传递控制权,或用res.send()
终止请求。 - 通过
app.use()
或路由方法注册中间件,注意执行顺序。
中间件是 Express 的核心思想,掌握它可以灵活处理各种请求场景,提高代码复用性。