---
title: Middleware
---

# Middleware

用于拓展 Modern.js 内置的 Web Server，与 [Hook](/apis/app/runtime/web-server/hook) 不同的是，Middleware 可以直接操作 Node 原生的请求、响应对象，并且可以使用框架拓展。

:::note

在下一个大版本，Modern.js 将会使用新 Middleware 来替代该写法。

推荐使用 [UnstableMiddleware](/apis/app/runtime/web-server/unstable_middleware) 处理页面请求。

:::

:::note

更多内容可以查看[自定义 Web Server](/guides/advanced-features/web-server)。

:::

## 使用姿势

```ts
import { Middleware } from '@modern-js/runtime/server';

export const middleware: Middleware = async (context, next) => {};
export const middleware: Middleware[] = [
  async (context, next) => {},
  async (context, next) => {},
];
```

:::info 自定义 Web Server
使用该 API 前，请先执行 `pnpm run new` 新建「自定义 Web Server」源码目录。

```bash
pnpm run new
? 请选择你想要的操作 创建工程元素
? 新建「自定义 Web Server」源码目录
```

:::

## 函数签名

```ts
type Middleware = (
  context: MiddlewareContext,
  next: NextFunction,
) => Promise<void> | void;

type MiddlewareContext = {
  response: {
    set: (key: string, value: string) => void;
    status: (code: number) => void;
    getStatus: () => number;
    cookies: {
      set: (key: string, value: string, options?: any) => void;
      clear: () => void;
    };
    raw: (
      body: string,
      { status, headers }: { status: number; headers: Record<string, any> },
    ) => void;
    locals: Record<string, any>;
  };
  request: {
    url: string;
    host: string;
    pathname: string;
    query: Record<string, any>;
    cookie: string;
    cookies: {
      get: (key: string) => string;
    };
    headers: IncomingHttpHeaders;
  };
  source: {
    req: IncomingMessage;
    res: ServerResponse;
  };
};
```

### 参数

- `context`：提供当前 Hook 上下文。
  - `response`：提供一系列处理响应的操作
  - `request`：提供一系列获取请求信息的操作
  - `source`：提供 Node.js 原生的 `req` 与 `res` 对象。
- `next`：执行当前 Hook 的下一个监听函数（不影响整体服务端流程）。

:::warning
`next` 函数的执行不影响后续内置流程，只控制下一个中间件是否执行。只有当响应被写入时，后续渲染流程才会中断。
:::

## 示例

### 服务端耗时打点

```ts
export const Middleware = () => async (ctx, next) => {
  const start = Date.now();
  ctx.source.res.once('finish', () => {
    console.log(Date.now() - start);
  });
};
```

### 注入服务端工具 & 数据

Modern.js 提供了 `response.locals` 属性用来存放当前请求的局部变量。

```ts
export const Middleware = () => async (ctx, next) => {
  ctx.response.locals.id = 'Modern.js';
  ctx.response.locals.rpc = createRpcInstance();
};
```

### 框架拓展

Middleware 还可以和 BFF 一样，使用运行时框架拓展。Modern.js 约定，当使用框架运行时拓展时，类型信息从 `@modern-js/runtime/{namespace}` 下导出，Middleware 可以使用框架语法，例如框架中间件写法，以下是伪代码：

```ts
import { SomeType } from '@modern-js/runtime/{namespace}';

export const middleware: SomeType = (ctx, next) => {
  console.log(ctx.url);
  next();
};
```

默认情况下，在安装框架拓展插件后，Web Server 的框架拓展能力是关闭的。如果希望使用框架拓展，可以通过 [`server.enableFrameworkExt`](/configure/app/server/enable-framework-ext.html) 开启。

:::info
框架拓展导出的类型名不一定为 Middleware，命名由框架拓展插件。
:::
