NestJS 中间件
基础语法
- 方式一:函数式中间件(无依赖注入能力)
轻量场景使用,本质是普通函数。
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() 传递请求,否则请求会挂起
}- 方式二:类式中间件(推荐,支持依赖注入)
需实现 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();
}
}- 方式三:原生 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
}
}