Nest AOP 是指在 Nest.js 框架中使用面向切面编程(Aspect-Oriented Programming)的技术。面向切面编程是一种编程范式,它允许开发者通过在代码中定义切面(Aspect),来将横切关注点(Cross-cutting Concerns)与核心业务逻辑进行解耦。
在 Nest.js 中,开发者可以使用 Nest AOP 模块来实现 AOP 功能。通过使用装饰器(Decorator)来定义切面,并使用注入依赖(Dependency Injection)来实现对切面的使用。Nest AOP 提供了一系列的装饰器和注解,开发者可以使用它们来在不修改原有代码的情况下,为应用程序的不同部分添加额外的行为。
使用 Nest AOP,开发者可以很方便地实现一些跟业务逻辑无关但又必要的功能,比如日志记录、性能监控、缓存等。同时,它也能提高代码的可维护性和可测试性,使应用程序更易于理解和扩展。
当请求过来,可能会经过 Controller(控制器)、Service(服务)、Repository(数据库访问) 的逻辑
当我们想在这些逻辑里加入一些通用逻辑该怎么加呢?
可能我们会直接想到在哪用到就在哪里增加代码,但是这样会造成通用的逻辑入侵到了业务代码里面,所以AOP (面向切面编程) 孕育而生,它的作用是一些通用逻辑分离到切面中,保持业务逻辑的纯粹性,这样切面逻辑可以复用,还可以动态的增删。
例如下图:
Nest 实现 AOP 的方式更多,一共有五种,包括 Middleware、Guard、Pipe、Interceptor、ExceptionFilter。
1、创建项目
首先我们先创建一个项目
nest new aop
2、中间件 Middleware
Nest中间件(Middleware)是一种用于处理HTTP请求和响应的中间层。它可以在处理请求之前和之后执行一些操作,例如验证请求、记录日志、处理异常等。
在Nest中,中间件是一个类或函数,它实现了NestMiddleware接口。在类中,可以使用use方法装饰器将该中间件注册到应用程序模块中。在函数中,可以使用@Middleware()装饰器将该中间件注册到相应的路由处理器上。
中间件可以被全局应用或只应用于特定的路由或控制器。全局中间件会应用于应用程序中所有的请求。而特定路由或控制器的中间件只会应用于指定的路由或控制器。
2.1、全局使用
在 main.ts 里通过 app.use 使用:
app.use(function (req: Request, res: Response, next: NextFunction) {
console.log('之前', req.url);
next();
console.log('之后');
})
在 app.controller.ts 中添加
@Get()
getHello(): string {
console.log('进入');
return this.appService.getHello();
}
接着启动项目
pnpm run start:dev
浏览器访问 http://localhost:3000/
可以看到控制台按照顺序打印出了 之前 进入 之后
这里其实和vue的router路由守卫差不多意思 在进入之前 可以进行一些逻辑判断 接着调用next() 就可进入 接着执行完成里面的内容之后 可以再进行一些操作
大家有兴趣可以多建几个接口测试一下 例如
@Get('www')
www(): string {
console.log('进入 www');
return '我调用了www'
}
接着我们游览器打开 http://localhost:3000/www 可以看到控制台
这就是全局中间件 Middleware 它可以让我们在调用接口之前 做一些逻辑复用 在处理请求之前和之后执行一些操作
2.1、路由使用
中间件 Middleware除了可以在全局使用 也支持路由中间件
首先 创建一个路由中间件:
nest g middleware log --no-spec --flat
–no-spec 是不生成测试文件 --flat 是平铺,不生成目录
可以看到生成以下代码
接着我们修改一下 log.middleware.ts
import {
Injectable, NestMiddleware } from '@nestjs/common';
@Injectable()
export class LogMiddleware implements NestMiddleware {
use(req: any, res: any, next: () => void) {
console.log('之前', req.url);
next();
console.log('之后');
}
}
并把之前的全局中间件 Middleware 注释掉
我们在 app.module.ts 的 AppModule 中 implements NestModule{,在 configure 方法里配置
consumer.apply(LogMiddleware).forRoutes(‘aaa*’);
此处是配置哪些路由生效
import {
MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import {
AppController } from './app.controller';
import {
AppService } from './app.service';
import {
LogMiddleware } from './log.middleware';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LogMiddleware).forRoutes('www*')
}
}
接着我们游览器打开 http://localhost:3000/www 可以看到控制台这就是全局中间件和路由中间件的区别。
3、路由守卫 Guard
NestJS 提供了一种称为 Guard 的路由守卫机制。Guard 可以用于保护路由,只有满足特定条件的请求才能继续执行路由处理程序。 可以用于在调用某个 Controller 之前判断权限,返回 true 或者 false 来决定是否放行
3.1、接口路由守卫
首先我们创建个 Guard:
nest g guard login --no-spec --flat
生成如下代码:
上面代码实现了CanActivate接口,用于判断用户是否具有激活路由的权限。canActivate方法接收一个ExecutionContext上下文对象作为参数,返回一个布尔值、Promise或Observable,用于表示是否可以激活对应的路由。
我们在代码这加入打印语句 接着把return 返回 false 代表只要调用了这个路由守卫 的接口 都是失败的
import {
CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import {
Observable } from 'rxjs';
@Injectable()
export class LoginGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
console.log('登录 校验');
return false;
}
}
接着我们在部分接口 使用 路由守卫 如下代码:(app.controller.ts)