# 中间件机制

URL: https://caijiao.org/koa/core/middleware
Source: docs/koa/core/middleware.md
Description: 了解 Koa 的中间件机制，包括中间件的执行顺序、生命周期、上下文传递机制以及如何编写自定义中间件。

Koa 的中间件机制是其核心功能之一，它通过异步方式处理请求和响应。中间件在 Koa 中以栈的形式组织，并且可以在请求处理过程中被动态注册，极大地提高了应用程序的灵活性和可维护性。理解 [Koa](/koa/) 中间件机制，有助于编写高效、可扩展的应用。

## 中间件的基本概念

中间件是处理 HTTP 请求和响应的函数，它们可以做以下操作：

- 处理请求（例如解析请求体、验证用户身份等）
- 修改响应（例如设置响应头、发送响应体等）
- 执行后续中间件

在 Koa 中，中间件具有以下结构：

```js
async function middleware(ctx, next) {
  // 在请求到达路由之前的操作
  await next(); // 调用下一个中间件
  // 在响应返回客户端之前的操作
}
````

- `ctx`：Koa 上下文对象，包含请求和响应的相关信息。
- `next`：表示调用下一个中间件的函数。`next()` 是一个异步操作，只有在 `next()` 被调用后，后续中间件才会继续执行。

## 中间件的执行顺序

Koa 中间件的执行顺序是基于栈（LIFO，后进先出）的。这意味着在请求过程中，中间件从上到下依次执行；但在响应返回时，中间件会反向执行。

### 示例：中间件的执行顺序

```js
const Koa = require('koa');
const app = new Koa();

// 第一个中间件
app.use(async (ctx, next) => {
  console.log('First middleware before next');
  await next();  // 调用下一个中间件
  console.log('First middleware after next');
});

// 第二个中间件
app.use(async (ctx, next) => {
  console.log('Second middleware before next');
  await next();
  console.log('Second middleware after next');
});

// 第三个中间件
app.use(async (ctx) => {
  console.log('Third middleware');
  ctx.body = 'Hello, Koa!';
});

app.listen(3000);
```

### 输出

```
First middleware before next
Second middleware before next
Third middleware
Second middleware after next
First middleware after next
```

在上述示例中，我们可以看到中间件的执行顺序：先执行第一个中间件，再执行第二个，最后执行第三个。在 `await next()` 被调用后，执行顺序反转，依次回到前面的中间件。

## 中间件的生命周期

Koa 中间件的生命周期可以分为以下两个阶段：

1. **请求阶段**：在请求到达路由之前，中间件会被按顺序执行。在这一阶段，你可以对请求进行处理，例如验证用户身份、解析请求体等。
2. **响应阶段**：当请求到达终端中间件时，中间件会生成响应，之后中间件会按相反的顺序执行，你可以在这一阶段修改响应数据。

### 示例：请求和响应阶段

```js
app.use(async (ctx, next) => {
  console.log('Request received');
  await next(); // 请求阶段完成后，继续执行响应阶段
  console.log('Response sent');
});
```

输出：

```
Request received
Response sent
```

## 中间件的上下文（`ctx`）

在 Koa 中，每个中间件接收一个上下文对象 `ctx`，它包含了请求和响应的所有信息。`ctx` 对象允许中间件在处理请求时访问和修改请求数据、设置响应数据等。

### 主要的 `ctx` 属性

- `ctx.request`：请求对象，包含请求的详细信息（如请求头、请求方法、请求体等）。
- `ctx.response`：响应对象，包含响应的详细信息（如响应头、响应体等）。
- `ctx.body`：用于设置响应体。
- `ctx.status`：设置响应状态码。
- `ctx.query`：包含 URL 查询参数。
- `ctx.params`：包含路由参数。

## 如何编写自定义中间件

Koa 允许开发者编写自定义中间件来扩展应用的功能。自定义中间件可以在请求过程中做任何处理，也可以在响应返回时做修改。

### 示例：自定义日志中间件

```js
app.use(async (ctx, next) => {
  const start = Date.now();
  await next(); // 执行下一个中间件
  const ms = Date.now() - start;
  console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});
```

这个中间件会记录每个请求的处理时间，帮助开发者了解请求的延迟。

### 示例：自定义错误处理中间件

```js
app.use(async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    ctx.status = err.status || 500;
    ctx.body = { message: err.message };
  }
});
```

这个中间件捕获应用中的错误，返回给客户端合适的错误信息。

## 总结

Koa 的中间件机制非常灵活且强大，它允许开发者以简单而高效的方式组织请求和响应处理。通过理解 Koa 中间件的执行顺序、生命周期以及如何编写自定义中间件，你可以构建出灵活、可扩展的应用程序。

Koa 中间件的执行模型使得请求和响应的处理非常模块化，易于管理和扩展，这也是 Koa 在构建高性能 Web 应用中的重要特点。
