在 Express.js
中,中间件是指那些可以处理请求对象(req
)、响应对象(res
)以及处理请求-响应周期的函数。中间件可以在请求被路由处理之前或之后执行,是 Express.js
的核心特性之一。它们使得应用程序更具灵活性和可维护性。
中间件工作原理
中间件函数可以接收三个参数:
req
: 请求对象,包含请求的所有信息(例如 URL、请求体、头部等)。res
: 响应对象,包含发送响应的方法(如 **res.send()、res.json()**)。next
: 函数,调用该函数可以将控制权传递给下一个中间件。如果不调用next()
,请求将被挂起,后续中间件和路由处理将不会被执行。
中间件类型
1.应用级中间件: 绑定到应用程序的实例上,通常用于处理全局的请求处理逻辑。
const express = require('express');
const app = express();
app.use((req, res, next) => {
console.log('请求时间:', new Date());
next(); // 继续处理请求
});
2.路由级中间件: 绑定到特定路由上,只有当访问该路由时才会执行。
const router = express.Router();
router.use('/admin', (req, res, next) => {
console.log('管理员路由访问');
next();
});
app.use(router);
3.内置中间件: Express.js
自带的一些中间件,比如 express.json()
和 express.urlencoded()
,用于解析请求体。
app.use(express.json()); // 解析 JSON 请求体
app.use(express.urlencoded({ extended: true })); // 解析 URL 编码的请求体
4.第三方中间件: 由社区开发的中间件,例如用于处理 CORS
的 cors
中间件,或用于处理文件上传的 multer
中间件。
const cors = require('cors');
app.use(cors()); // 启用 CORS
5.错误处理中间件: 用于处理错误的中间件,具有四个参数(err
、req
、res
、next
)。这些中间件会捕获应用中的错误。
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
使用场景
- 日志记录: 记录请求信息、时间、请求方法等。
- 身份验证: 验证用户是否登录或具有权限。
- 数据验证: 验证请求体中数据的合法性。
- 设置响应头: 配置 CORS、内容类型等响应头。
- 错误处理: 捕获并处理错误,返回友好的错误信息。
举几个例子
日志记录中间件:一个简单的中间件,用于记录每个请求的 HTTP 方法和 URL。
const express = require('express');
const app = express();
// 日志中间件
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next(); // 继续处理请求
});
// 示例路由
app.get('/', (req, res) => {
res.send('Hello World!');
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
身份验证中间件: 就是上一篇的JWT
const jwt = require('jsonwebtoken');
const express = require('express');
const app = express();
const SECRET_KEY = 'summer889';
// 身份验证中间件
function authenticateToken(req, res, next) {
const token = req.headers['authorization']?.split(' ')[1]; // 从头部获取 JWT
if (!token) return res.sendStatus(401); // 没有令牌,返回 401
jwt.verify(token, SECRET_KEY, (err, user) => {
if (err) return res.sendStatus(403); // 令牌无效,返回 403
req.user = user; // 将用户信息存储在请求对象中
next(); // 继续处理请求
});
}
// 受保护的路由
app.get('/protected', authenticateToken, (req, res) => {
res.json({ message: '这是一个保护路由', user: req.user });
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
数据验证中间件:用 express-validator
来验证请求体中的数据是否合法。**(专门治疗跨部门)**
const { body, validationResult } = require('express-validator');
const express = require('express');
const app = express();
app.use(express.json());
// 数据验证中间件
app.post('/register',
body('username').isLength({ min: 5 }), // 用户名长度至少为 5
body('password').isLength({ min: 6 }), // 密码长度至少为 6
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
res.send('注册成功!');
}
);
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
错误处理中心件:处理应用中的错误,返回统一的错误响应。
const express = require('express');
const app = express();
app.use(express.json());
// 示例路由
app.get('/', (req, res) => {
throw new Error('这是一个示例错误'); // 抛出错误
});
// 错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack); // 打印错误堆栈
res.status(500).json({ error: '发生了一个错误!' }); // 返回错误信息
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
中间件是处理请求和响应周期的重要组成部分,提供了极大的灵活性和可扩展性,没用过Koa不知道,但我感觉Express
非常香。