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 - 区别是啥?
| 特性 | Middleware | Interceptor |
|---|---|---|
| 能否拿到目标 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 类比 | 作用 |
|---|---|---|
| Middleware | router.beforeEach | 请求前后执行逻辑 |
| NestModule | - | 注册 Middleware |
| MiddlewareConsumer | - | 精确控制作用于哪些路由 |
一句话总结:
Nest 的 Middleware 就是支持依赖注入的路由守卫,可以在请求前后执行通用逻辑。
和 Express 的区别:Express 的 middleware 是函数,Nest 的 middleware 是 class(支持依赖注入)。