# 中间件迁移指南

URL: https://caijiao.org/fastify/appendix/middleware-migration
Source: docs/fastify/appendix/middleware-migration.md
Description: 本节介绍如何在 Fastify 中迁移中间件，帮助开发者从其他框架（如 Express）迁移到 Fastify，理解 Fastify 中间件的工作方式，并学习如何正确使用它们。

迁移现有应用到 [Fastify](/fastify/) 时，如何处理中间件是一个重要问题。虽然 Fastify 和一些传统框架（如 Express）都支持中间件，但它们的实现和使用方式有所不同。本节将详细介绍如何将传统框架中的中间件迁移到 Fastify，并解决常见的迁移问题。

## 1. Fastify 中间件与其他框架的区别

在其他框架中，中间件通常用于请求生命周期中的不同阶段，比如请求处理、路由前的处理、响应后处理等。Fastify 也有类似的概念，但它采用了一个更高效的处理方式，基于 [Fastify](/fastify/) 生命周期和插件机制。

### 1.1 Express 中间件的工作方式

在 Express 中，中间件是通过 `app.use()` 方法来注册的，并且可以访问请求和响应对象。Express 中间件通常在请求被处理之前或之后执行。

### 1.2 Fastify 中间件的工作方式

Fastify 使用装饰器和钩子（hooks）来注册中间件。与 Express 中间件不同，[Fastify](/fastify/) 中的中间件更接近于插件的实现。Fastify 允许你在请求生命周期的各个阶段插入中间件，但它具有更强的性能和灵活性。

## 2. Express 中间件迁移到 Fastify

迁移一个简单的 Express 中间件到 Fastify，可以按照以下步骤进行。

### 2.1 Express 中间件示例

假设你有以下的 Express 中间件，用于打印请求信息：

```js
// Express 中间件
app.use((req, res, next) => {
  console.log(`Request received at ${new Date().toISOString()}`);
  next();
});
```

### 2.2 在 Fastify 中迁移

在 Fastify 中，你可以使用 `fastify.addHook` 或插件系统来完成相同的任务。以下是将上述 Express 中间件迁移到 Fastify 的方法：

```js
// Fastify 中间件
const fastify = require('fastify')();

fastify.addHook('onRequest', async (request, reply) => {
  console.log(`Request received at ${new Date().toISOString()}`);
});
```

在 Fastify 中，`onRequest` 是一个生命周期钩子，它在请求到达路由处理程序之前执行。通过这种方式，Fastify 实现了类似于 Express 中间件的功能。

## 3. 迁移复杂的 Express 中间件

### 3.1 Express 异常处理器

假设你在 Express 中使用了一个异常处理器：

```js
// Express 中的异常处理中间件
app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).send('Internal Server Error');
});
```

### 3.2 在 Fastify 中迁移

Fastify 使用 `onError` 钩子来处理错误。你可以通过注册 `onError` 钩子来迁移错误处理中间件：

```js
// Fastify 中的异常处理
fastify.setErrorHandler((error, request, reply) => {
  console.error(error);
  reply.status(500).send('Internal Server Error');
});
```

Fastify 的 `setErrorHandler` 方法允许你在应用级别定义错误处理程序，它会捕获所有请求的未处理错误。

### 3.3 Express 路由级中间件

Express 中常见的做法是为特定路由添加中间件：

```js
// Express 路由级中间件
app.get('/user/:id', (req, res, next) => {
  console.log('User ID:', req.params.id);
  next();
}, (req, res) => {
  res.send('User Info');
});
```

### 3.4 在 Fastify 中迁移

Fastify 支持路由级别的中间件，可以直接在路由定义中使用：

```js
// Fastify 路由级中间件
fastify.get('/user/:id', async (request, reply) => {
  console.log('User ID:', request.params.id);
  return 'User Info';
});
```

与 Express 不同，Fastify 将中间件和路由处理程序合并在一起，因此你可以直接在路由内执行需要的操作。

## 4. 注意事项

### 4.1 性能优化

Fastify 的中间件机制是为高性能设计的。与 Express 不同，Fastify 插件和中间件机制使用了严格的生命周期钩子，这意味着你的中间件不会无意中添加不必要的开销。尽量避免使用过多的全局中间件，在 Fastify 中，最好使用插件来控制中间件的作用范围。

### 4.2 异步操作支持

Fastify 中的钩子和中间件是异步的，因此可以直接使用 `async` 函数进行异步操作，避免回调地狱。例如，你可以在中间件中执行异步操作如数据库查询、文件操作等。

```js
fastify.addHook('onRequest', async (request, reply) => {
  const result = await someAsyncOperation();
  console.log(result);
});
```

## 5. 总结

Fastify 提供了强大的中间件和插件机制，可以帮助你迁移现有的 Express 中间件。理解 Fastify 的生命周期钩子是迁移过程中的关键。通过使用适当的钩子和插件，你可以高效地迁移和扩展你的 Fastify 应用，并充分利用其高性能的优势。
