Nest 中间件 Middleware - 就像 Vue 的路由守卫

0 阅读2分钟

1. 先说 Vue 里的"中间件"

你有没有在 Vue 里用过这些?

场景一:路由守卫

// Vue 路由守卫
router.beforeEach((to, from, next) => {
  console.log('跳转前');
  next();  // 放行
});

每次页面跳转,都会先经过这个"拦截器"。

场景二:axios 请求拦截器

// 请求发送前
axios.interceptors.request.use(config => {
  config.headers.Authorization = 'Bearer token';
  return config;
});

这就是中间件的思想:在请求进入之前、响应返回之后,偷偷干点别的事


2. Nest 的 Middleware 是什么?

Nest 也有中间件,但和 Express 的不完全一样。

最大区别:Nest 的 Middleware 支持依赖注入

@Injectable()
export class AaaMiddleware implements NestMiddleware {
  // 可以注入 Service!
  @Inject(AppService)
  private readonly appService: AppService;

  use(req: Request, res: Response, next: () => void) {
    console.log('请求前');
    next();  // 放行
    console.log('响应后');
  }
}

3. 怎么用?三步走

第 1 步:创建 Middleware

nest g middleware aaa --no-spec --flat

第 2 步:写业务逻辑

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response } from 'express';

@Injectable()
export class AaaMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: () => void) {
    console.log('请求前');
    next();  // 放行到下一个中间件或 Controller
    console.log('响应后');
  }
}

第 3 步:在 Module 中注册

@Module({
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(AaaMiddleware).forRoutes('*');  // 作用于所有路由
  }
}

4. 可以精确控制作用于哪些路由

configure(consumer: MiddlewareConsumer) {
  // 只作用于 /hello 开头的 GET 请求
  consumer.apply(AaaMiddleware).forRoutes({
    path: 'hello*',
    method: RequestMethod.GET
  });
}

对比 Vue

// Vue 中精确控制
router.beforeEach((to, from, next) => {
  if (to.path.startsWith('/hello')) {
    console.log('只拦截 /hello 开头');
  }
  next();
});

5. 为什么要用 Class 形式的 Middleware?

当然是为了依赖注入

@Injectable()
export class AaaMiddleware implements NestMiddleware {
  // 可以注入别的 Service!
  constructor(private readonly appService: AppService) {}

  use(req: Request, res: Response, next: () => void) {
    // 调用 Service 的方法
    console.log(this.appService.getHello());
    next();
  }
}

Vue 对比:Vue 的路由守卫里也可以调用 Vuex/Pinia 的 actions!


6. 不注入依赖?也可以用函数形式

// 如果不需要注入依赖,可以简写成函数
const loggerMiddleware = (req, res, next) => {
  console.log('请求前');
  next();
};

configure(consumer: MiddlewareConsumer) {
  consumer.apply(loggerMiddleware).forRoutes('*');
}

这就和 Express 的 middleware 一样了。


7. Middleware vs Interceptor - 区别是啥?

特性MiddlewareInterceptor
能否拿到目标 Handler❌ 不能✅ 可以
能否用 RxJS❌ 不能✅ 可以
适用场景通用逻辑(日志、CORS)业务相关(统一返回格式)
// Interceptor 可以拿到目标 Handler
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
  const handler = context.getHandler();  // 拿到目标方法
  console.log('目标:', handler);
  return next.handle();
}

Vue 对比

  • Middleware = 路由守卫(通用)
  • Interceptor = axios 拦截器(业务相关)

8. 完整流程图

请求进来
   │
   ▼
┌──────────────────────────────────────┐
│  Middleware(请求前后)               │  ← 可以在这里打印日志、权限校验
└──────────────────────────────────────┘
   │
   ▼
┌──────────────────────────────────────┐
│  Guard(权限判断)                   │
└──────────────────────────────────────┘
   │
   ▼
┌──────────────────────────────────────┐
│  Interceptor(响应前后)              │  ← 可以统一处理返回值、计时
└──────────────────────────────────────┘
   │
   ▼
  Controller(业务逻辑)

9. 总结

概念Vue 类比作用
Middlewarerouter.beforeEach请求前后执行逻辑
NestModule-注册 Middleware
MiddlewareConsumer-精确控制作用于哪些路由

一句话总结

Nest 的 Middleware 就是支持依赖注入的路由守卫,可以在请求前后执行通用逻辑。

和 Express 的区别:Express 的 middleware 是函数,Nest 的 middleware 是 class(支持依赖注入)。