在上一节里, 我们学习了模块、控制器、提供者, 讲述了最简 API 编写流程. 这一节里, 我们学习 AOP(面向切面编程), NestJS 是 MVC 与 AOP 结合的框架结构.
AOP(Aspect Oriented Programming): 是一种面向切面编程的编程思想.
在 NestJS 中, 一个请求进来, 会经过控制器 C 到模型 M 的流程, AOP 是从切面的插进去, AOP 在 NestJS 用到的功能为中间件(日志等)、异常过滤器(异常处理)、管道(数据验证、转换)、守卫守卫(权限)、拦截器(日志、数据转换、Stream).
中间件
中间件是在路由处理程序 之前 调用的函数。 中间件函数可以访问请求和响应对象,以及应用程序请求响应周期中的 next() 中间件函数。 next() 中间件函数通常由名为 next 的变量表示。
- 执行任何代码。
- 对请求和响应对象进行更改。
- 结束请求-响应周期。
- 调用堆栈中的下一个中间件函数。
- 如果当前的中间件函数没有结束请求-响应周期, 它必须调用
next()将控制传递给下一个中间件函数。否则, 请求将被挂起。
写法
logger.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
console.log('Request...');
next();
}
}
引入方法
依赖注入
app.module.ts
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes('cats'); // 包含路由路径
// .forRoutes({ path: 'cats', method: RequestMethod.GET }); // 请求方法
// .forRoutes({ path: 'ab*cd', method: RequestMethod.ALL }); // 通配符
}
}
全局
main.ts
const app = await NestFactory.create(AppModule);
app.use(logger); // 注册中间件
await app.listen(3000);
异常过滤器
内置的异常层负责处理整个应用程序中的所有抛出的异常。当捕获到未处理的异常时,最终用户将收到友好的响应。
cats.controller.ts
@Get()
async findAll() {
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
}
响应
{ "statusCode": 403, "message": "Forbidden" }
自定义异常过滤器
http-exception.filter.ts
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';
@Catch(HttpException) // 抛出的 HttpException 异常都到这里, 传递多个参数,用逗号分隔
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception.getStatus();
response
.status(status)
.json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
绑定过滤器
cats.controller.ts
@Post()
@UseFilters(HttpExceptionFilter)
async create(@Body() createCatDto: CreateCatDto) {
throw new ForbiddenException();
}
全局
main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new HttpExceptionFilter()); // 全局绑定过滤器
await app.listen(3000);
}
bootstrap();
捕获异常
为了捕获每一个未处理的异常(不管异常类型如何),将 @Catch() 装饰器的参数列表设为空,例如 @Catch()。
any-exception.filter.ts
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
HttpStatus,
} from '@nestjs/common';
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
以上就是简单的记录一下, 详情可以看官方文档