Skip to content

ExpressJS - 中间件

中间件(Middleware)函数是 Express.js 的核心。它们是能够访问请求对象(req)、响应对象(res)以及应用程序请求-响应周期中的 next 函数的函数。中间件可以执行任何代码,修改请求和响应对象,终止请求-响应周期,或者调用堆栈中的下一个中间件。

可以将中间件想象成请求必须通过的一系列检查点。在每个检查点,您都可以检查、修改甚至拒绝请求。

Express 中间件可以分为以下几种类型:

  • 应用级中间件: 使用 app.use() 或 app.METHOD() 绑定到应用程序对象 app 上。
  • 路由级中间件: 工作方式与应用级中间件相同,但绑定到 express.Router() 实例上。
  • 错误处理中间件: 具有 (err, req, res, next) 的特殊签名,用于处理错误。
  • 内置中间件: Express 包含的标准中间件函数,例如 express.json() 和 express.static()。
  • 第三方中间件: 可作为 npm 包使用的中间件,如 helmet 或 morgan。

让我们创建一个简单的日志中间件,用于打印每个传入请求的时间戳和方法。

示例:一个简单的请求日志记录器

Section titled “示例:一个简单的请求日志记录器”
import express from 'express';
const app = express();
const PORT = 3000;
// Custom logger middleware
const requestLogger = (req, res, next) => {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] ${req.method} ${req.originalUrl}`);
// 这个函数调用至关重要!它将控制权传递给下一个中间件。
// 如果没有它,请求将一直挂起。
next();
};
// Apply the middleware to all routes
app.use(requestLogger);
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.get('/about', (req, res) => {
res.send('This is the about page.');
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});

当您运行此服务器并访问 http://localhost:3000/ 时,您的控制台将显示:

Server is running on http://localhost:3000
[2023-10-27T10:30:00.123Z] GET /

您可以通过将路径作为 app.use() 的第一个参数来将中间件应用于特定路由或一组路由。

const adminAuth = (req, res, next) => {
// 在实际应用中,您会检查身份验证凭据
console.log('Admin auth check passed!');
next();
};
// 此中间件仅对 /admin 及其子路由的请求运行
app.use('/admin', adminAuth);
app.get('/admin/dashboard', (req, res) => {
res.send('Welcome to the Admin Dashboard');
});

中间件函数按顺序执行,因此您包含它们的顺序至关重要。请求将逐一通过它们。

// 中间件 1:第一个执行
app.use((req, res, next) => {
console.log('First Middleware: Setting request time');
req.requestTime = Date.now();
next();
});
// 中间件 2:第二个执行
app.use((req, res, next) => {
console.log('Second Middleware: Logging request time');
console.log(`Request received at: ${new Date(req.requestTime).toLocaleTimeString()}`);
next();
});
app.get('/', (req, res) => {
res.send(`Request was processed.`);
});

如果一个中间件函数不调用 next(),它必须自行终止请求-响应周期(例如,通过调用 res.send() 或 res.json())。否则,请求将挂起。

Express 带有功能强大的内置中间件,而 npm 生态系统为常见任务提供了无数更多的中间件。

内置:express.json() 和 express.urlencoded()

Section titled “内置:express.json() 和 express.urlencoded()”

以前,需要 body-parser 包来解析传入的请求体。此功能现在已直接内置于 Express 中。

// 用于解析 JSON 格式的请求体
app.use(express.json());
// 用于解析 URL 编码的请求体(例如,来自 HTML 表单)
app.use(express.urlencoded({ extended: true }));
app.post('/api/users', (req, res) => {
// req.body 现在填充了已解析的数据
const newUser = req.body;
console.log(newUser);
res.status(201).json(newUser);
});

此中间件解析 Cookie 头,并使用以 cookie 名称为键的对象填充 req.cookies。

# 安装
npm install cookie-parser
# 使用
import cookieParser from 'cookie-parser';
app.use(cookieParser());
app.get('/set-cookie', (req, res) => {
res.cookie('username', 'john.doe', { httpOnly: true });
res.send('Cookie has been set!');
});
app.get('/read-cookie', (req, res) => {
// 从 req.cookies 访问 cookie
const username = req.cookies.username;
res.send(`Hello, ${username}!`);
});

morgan 是一个流行的 HTTP 请求日志中间件。它比我们自定义的日志记录器更强大,并且高度可配置,适用于生产环境。

# 安装
npm install morgan
# 使用
import morgan from 'morgan';
// 在开发过程中使用 'dev' 格式以获取简洁、带有颜色编码的日志
app.use(morgan('dev'));