Middleware

用于拓展 Modern.js 内置的 Web Server,与 Hook 不同的是,Middleware 可以直接操作 Node 原生的请求、响应对象,并且可以使用框架拓展。

NOTE

更多内容可以查看自定义 Web Server

使用姿势

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

export const middleware: Middleware = async (context, next) => {};
export const middleware: Middleware[] = [
  async (context, next) => {},
  async (context, next) => {},
];
自定义 Web Server

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

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

函数签名

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

type MiddlewareContext = {
  response: {
    set: (key: string, value: string) => void;
    status: (code: number) => void;
    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 原生的 reqres 对象。
  • next:执行当前 Hook 的下一个监听函数(不影响整体服务端流程)。
WARNING

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

示例

服务端耗时打点

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

注入服务端工具 & 数据

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

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 可以使用框架语法,例如框架中间件写法,以下是伪代码:

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

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

默认情况下,在安装框架拓展插件后,Web Server 的框架拓展能力是关闭的。如果希望使用框架拓展,可以通过 server.enableFrameworkExt 开启。

INFO

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