异常过滤器
内置的异常层负责处理整个应用程序中的所有抛出的异常。当捕获到未处理的异常时,最终用户将收到友好的响应。
开箱即用,此操作由内置的全局异常过滤器执行,该过滤器处理类型 HttpException
(及其子类)的异常。每个发生的异常都由全局异常过滤器处理, 当这个异常无法被识别时 (既不是 HttpException
也不是继承自 HttpException
的类 ) , 用户将收到以下 JSON
响应:
{
"statusCode": 500,
"message": "Internal server error"
}
HttpException
构造函数有两个必要的参数来决定响应:
response: string | object
定义JSON
响应体;status: number
定义HTTP
HTTP响应状态码,最佳实践是使用内置的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
,需进一步了解。