Skip to content

中间件

什么是中间件

中间件是 Express 应用中的一个函数,它可以访问请求对象(req)、响应对象(res)以及应用的请求-响应循环中的下一个中间件函数(next)。中间件函数可以执行以下任务:

  • 执行任何代码
  • 修改请求和响应对象
  • 结束请求-响应循环
  • 调用下一个中间件函数

中间件的类型

1. 应用级中间件

应用级中间件绑定到 Express 应用实例上,使用 app.use()app.METHOD() 方法。

javascript
// 应用于所有请求
app.use((req, res, next) => {
  console.log('Time:', Date.now());
  next();
});

// 应用于特定路径
app.use('/users', (req, res, next) => {
  console.log('Users route');
  next();
});

// 应用于特定路径和方法
app.get('/users', (req, res, next) => {
  console.log('GET /users');
  next();
}, (req, res) => {
  res.send('Users');
});

2. 路由级中间件

路由级中间件与应用级中间件类似,但它绑定到 express.Router() 实例上。

javascript
const router = express.Router();

// 应用于所有路由
router.use((req, res, next) => {
  console.log('Time:', Date.now());
  next();
});

// 应用于特定路由
router.use('/:id', (req, res, next) => {
  console.log('User ID:', req.params.id);
  next();
});

app.use('/users', router);

3. 错误处理中间件

错误处理中间件有四个参数:err, req, res, next

javascript
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

4. 内置中间件

Express 内置了以下中间件:

  • express.static():提供静态文件服务
  • express.json():解析 JSON 请求体
  • express.urlencoded():解析 URL 编码的请求体
javascript
// 提供静态文件服务
app.use(express.static('public'));

// 解析 JSON 请求体
app.use(express.json());

// 解析 URL 编码的请求体
app.use(express.urlencoded({ extended: true }));

5. 第三方中间件

可以使用第三方中间件来扩展 Express 应用的功能。

bash
npm install morgan helmet cors
javascript
const morgan = require('morgan');
const helmet = require('helmet');
const cors = require('cors');

// 日志中间件
app.use(morgan('dev'));

// 安全中间件
app.use(helmet());

// 跨域中间件
app.use(cors());

中间件的执行顺序

中间件的执行顺序取决于它们在代码中的定义顺序。

javascript
// 第一个执行
app.use((req, res, next) => {
  console.log('Middleware 1');
  next();
});

// 第二个执行
app.use((req, res, next) => {
  console.log('Middleware 2');
  next();
});

// 第三个执行
app.get('/', (req, res) => {
  res.send('Hello World!');
});

中间件链

可以将多个中间件函数链接在一起,形成一个中间件链。

javascript
app.get('/user/:id', 
  (req, res, next) => {
    console.log('First middleware');
    next();
  },
  (req, res, next) => {
    console.log('Second middleware');
    next();
  },
  (req, res) => {
    res.send(`User ${req.params.id}`);
  }
);

中间件的错误处理

如果中间件函数中发生错误,应该调用 next(err) 将错误传递给错误处理中间件。

javascript
app.get('/user/:id', (req, res, next) => {
  const id = parseInt(req.params.id);
  if (isNaN(id)) {
    const error = new Error('Invalid user ID');
    error.status = 400;
    return next(error);
  }
  next();
}, (req, res) => {
  res.send(`User ${req.params.id}`);
});

// 错误处理中间件
app.use((err, req, res, next) => {
  res.status(err.status || 500).send(err.message);
});

中间件的最佳实践

1. 保持中间件简洁

  • 每个中间件只负责一个功能
  • 中间件代码应该简洁明了
  • 避免在中间件中执行复杂的业务逻辑

2. 合理使用中间件

  • 只使用必要的中间件
  • 避免过多的中间件
  • 合理安排中间件的顺序

3. 错误处理

  • 正确处理中间件中的错误
  • 使用统一的错误处理中间件
  • 提供清晰的错误信息

4. 安全性

  • 使用安全中间件(如 helmet)
  • 验证用户输入
  • 防止 XSS 和 CSRF 攻击

5. 性能优化

  • 避免在中间件中执行 CPU 密集型操作
  • 合理使用缓存
  • 只在必要的路由上应用中间件

常用的第三方中间件

1. 日志中间件

  • morgan:HTTP 请求日志
  • winston:多传输日志

2. 安全中间件

  • helmet:安全头设置
  • cors:跨域资源共享
  • express-rate-limit:请求速率限制

3. 认证中间件

  • passport:认证框架
  • express-jwt:JWT 认证

4. 验证中间件

  • express-validator:请求验证
  • joi:对象验证
  • express-session:会话管理
  • cookie-parser:Cookie 解析

实践练习

  1. 创建自定义中间件
  2. 使用第三方中间件
  3. 构建中间件链
  4. 实现错误处理中间件
  5. 优化中间件性能

基于 VitePress 的本地知识库