Skip to content

NestJS 中间件

基础语法

  1. 方式一:函数式中间件(无依赖注入能力)

轻量场景使用,本质是普通函数。

ts
// 直接定义一个函数,接收 req、res、next 三个参数(与 Express/Koa 一致)

// src/middleware/logger.middleware.ts
import { Request, Response, NextFunction } from 'express';

// Express 风格(默认)
export function loggerMiddleware(req: Request, res: Response, next: NextFunction) {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl}`);
  next(); // 必须调用 next() 传递请求,否则请求会挂起
}
  1. 方式二:类式中间件(推荐,支持依赖注入)

需实现 NestMiddleware 接口(核心方法 use),Nest 会自动实例化并支持依赖注入。

ts
// src/middleware/logger.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable() // 必须加,支持依赖注入
export class LoggerMiddleware implements NestMiddleware {
  // 可选:注入其他服务
  constructor(private readonly someService: SomeService) {}

  use(req: Request, res: Response, next: NextFunction) {
    console.log(`[类式中间件] ${req.method} ${req.originalUrl}`);
    // 可调用注入的服务
    this.someService.doSomething();
    next();
  }
}
  1. 方式三:原生 Express/Fastify 中间件
ts
// 复用 Express 原生中间件(如 cors、helmet)
import * as cors from 'cors';
import * as helmet from 'helmet';

// 在全局注册中直接使用
app.use(cors({ origin: '*' }));
app.use(helmet());

参数说明

shell
# Express 为例,最常用
参数名 类型                说明
req    Request (express)   请求对象,包含 URL、请求头、参数、body、IP 等所有请求信息
res   Response (express)   响应对象,用于设置响应头、状态码、返回数据等
next  NextFunction         回调函数,调用后将请求传递给下一个中间件 / 路由处理器;若不调用则终止请求

多个中间件的执行顺序

全局中间件 > 模块级中间件

洋葱模型:进入时正序,退出时逆序

ts
// 模块级注册顺序
consumer
  .apply(MiddlewareA, MiddlewareB, MiddlewareC) // 执行顺序:A(进) → B(进) → C(进) → 控制器 → C(出) → B(出) → A(出)
  .forRoutes('*');

异步中间件

中间件的 use 方法支持 async/await,需注意:异步操作完成后再调用 next(),避免请求提前终止。

ts
// src/middlewares/auth.middleware.ts
import { Injectable, NestMiddleware, UnauthorizedException } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { AuthService } from './auth.service';

@Injectable()
export class AuthMiddleware implements NestMiddleware {
  // 注入 AuthService(依赖注入)
  constructor(private readonly authService: AuthService) {}

  // 异步 use 方法
  async use(req: Request, res: Response, next: NextFunction) {
    const token = req.headers.authorization?.split(' ')[1];
    if (!token) {
      throw new UnauthorizedException('Token missing');
    }

    // 异步校验 token
    const user = await this.authService.verifyToken(token);
    if (!user) {
      throw new UnauthorizedException('Invalid token');
    }

    // 挂载用户信息到 req 对象
    req.user = user;
    next(); // 异步操作完成后调用 next
  }
}