异常过滤器
内置的异常层负责处理整个应用程序中的所有抛出的异常。当捕获到未处理的异常时,最终用户将收到友好的响应。
开箱即用,此操作由内置的全局异常过滤器执行,该过滤器处理类型
HttpException(及其子类)的异常。每个发生的异常都由全局异常过滤器处理, 当这个异常无法被识别时 (既不是 HttpException 也不是继承自 HttpException的类 ) , 用户将收到以下 JSON 响应:
{
"statusCode": 500,
"message": "Internal server error"
}
HttpException 构造函数有两个必要的参数来决定响应:
response: string | object定义JSON响应体;status: number定义HTTPHTTP响应状态码,最佳实践是使用内置的HttpStatus枚举。
默认情况下,JSON 响应体包含两个属性:
statusCode:默认为status参数中提供的HTTP状态码message:基于状态的HTTP错误的简短描述
如果response类型为string,则仅覆盖 JSON 响应主体的message部分;
如果response类型为object,Nest将序列化对象,并将其作为响应体返回。
自定义异常过滤器
import {
ArgumentsHost,
ExceptionFilter,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { Response, Request } from 'express';
export class HttpFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const statusCode =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
response.status(statusCode).json({
statusCode,
data: null,
success: false,
message: exception?.message ?? 'Internal server error',
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
ArgumentsHost类提供了获取传递给处理程序参数的方法,可以把ArgumentsHost看作处理程序参数的抽象,调用其getArgs方法可获取封装Express的 [request, response, next]数组对象。
Nest提供了ArgumentsHost的实例,作为host参数提供给catch方法,host.switchToHttp()返回适用于HTTP应用程序上下文的 HttpArgumentsHost类型的ctx对象,ctx对象有两个有用的方法,可以用来获取所需的requset和response对象,这里利用这两个对象对异常进行统一错误返回。
拦截器可以是控制器作用域内的, 方法作用域内的或者全局作用域内的。如果是作用于控制器或者方法,可直接使用从 @nestjs/common 包导入的 @UseFilters() 装饰器并传入类型(让Nest创建实例并依赖注入)或者传入匿名对象;如果是作用于全局的,则需要在入口文件使用Nest应用程序实例的 useGlobalFilters() 方法注册:
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new HttpFilter());
拦截器
拦截器是使用 @Injectable() 装饰器注解的类。拦截器应该实现 NestInterceptor 接口。
拦截器具有一系列有用的功能,这些功能受面向切面编程(
AOP)技术的启发。它们可以:
- 在函数执行之前/之后绑定额外的逻辑
- 转换从函数返回的结果
- 转换从函数抛出的异常
- 扩展基本函数行为
- 根据所选条件完全重写函数 (例如, 缓存目的)
定义拦截器
定义一个规范返回数据的拦截器:
import {
CallHandler,
ExecutionContext,
HttpStatus,
Injectable,
NestInterceptor,
} from '@nestjs/common';
import { map, Observable } from 'rxjs';
interface IResponseData<T> {
data: T;
}
@Injectable()
export class HttpInterceptor<T> implements NestInterceptor {
intercept(
context: ExecutionContext,
next: CallHandler<T>,
): Observable<IResponseData<T>> {
return next.handle().pipe(
map((data) => ({
statusCode: HttpStatus.OK,
data,
success: true,
message: 'success',
})),
);
}
}
ExecutionContext扩展了ArgumentsHost。和ArgumentsHost一样,Nest提供了ExecutionContext的实例,作为context参数提供给intercept方法。
CallHandler。如果不手动调用 handle() 方法,则处理程序根本不会被执行,只有 handle() 被调用(并且已返回其 Observable ),才会触发处理程序。一旦通过 Observable 接收到响应流,就可以对流执行其他操作,并将最终结果返回给调用方。
拦截器可以是控制器作用域内的, 方法作用域内的或者全局作用域内的。如果是作用于控制器或者方法,可直接使用从 @nestjs/common 包导入的 @UseInterceptors() 装饰器并传入类型(让Nest创建实例并依赖注入)或者传入匿名对象;如果是作用于全局的,则需要在入口文件使用Nest应用程序实例的 useGlobalInterceptors() 方法注册:
const app = await NestFactory.create(AppModule);
app.useGlobalInterceptors(new HttpInterceptor());
总结
本文主要记录了Nest异常过滤器和拦截器的基本概念和基础用法,对于拦截器的参数中CallHandler对象,由于涉及到rxjs,需进一步了解。