NestJS 中 HttpException
为基础异常类。
我们可以在应用程序中通过 new HttpException(响应体, HTTP 状态码)
创建该异常并抛出。
这里的 HTTP 状态码
可以从 NestJS 内置的 HttpStatus
枚举中获取。
@Get()
findAll() {
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
}
现在当客户端调用这个路由函数时,响应如下所示:
{
"statusCode": 403,
"message": "Forbidden"
}
NestJS 内置了一系列继承自 HttpException
的异常:
异常过滤器可捕获异常,并向前端返回友好的响应内容。
NestJS 内置了一个全局过滤器,该过滤器会处理 HttpException
(及其子类) 的异常。当这个异常无法被识别时 (不是 HttpException
(及其子类) 的异常),用户会收到一下 JSON 响应:
{
"statusCode": 500,
"message": "Internal server error"
}
可以使用 Nest-Cli 的命令 nest g filter XXX
/ nest g f XXX
创建一个过滤器的基础框架。
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
} from '@nestjs/common';
import { Request, Response } from 'express';
@Catch(HttpException) // 捕获 HttpException 错误; 如果 @Catch() 里面没有参数, 则捕获所有错误
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp(); // 获取上下文
const status = exception.getStatus(); // 获取状态码
// 通过上下文获取请求和响应
const request = ctx.getRequest<Request>();
const response = ctx.getResponse<Response>();
// 自定义响应
response.status(status).json({
status,
method: request.method,
path: request.url,
data: exception.message || exception.name,
time: new Date().toLocaleString(),
});
}
}
上例的 @Catch(XXX)
中,XXX
为该过滤器需要捕获的异常。如果不写,则表示捕获所有异常。@Catch()
可以传递多个参数,参数之间用 ,
隔开。
NestJS 中有 [全局]、[控制器]、[路由] 过滤器
Global 过滤器
使用 app.useGlobalFilters()
注册;全局过滤器只能有一个
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpExceptionFilter } from './filters/http-exception.filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new HttpExceptionFilter()); // 注册 Global 过滤器
await app.listen(3000);
}
bootstrap();
Controller 过滤器
使用 @UseFilters()
注册;多个过滤器之间用 ,
隔开
@Controller('project')
@UseFilters(new HttpExceptionFilter()) // 注册 Controller 过滤器
export class ProjectController {}
Route 过滤器
使用 @UseFilters
注册;多个过滤器之间用 ,
隔开
@Post()
@UseFilters(new HttpExceptionFilter()) // 注册 Route 过滤器
create(@Body() createCatDto: CreateCatDto) {}
过滤器的使用
因为 Nest 可以轻松地在整个模块中重复使用同一类的实例,所以注册过滤器时不使用实例注册 而直接使用类注册可以减少内存的开销。
@Post()
@UseFilters(HttpExceptionFilter) // 直接使用类进行注册
create(@Body() createCatDto: CreateCatDto) {}