7. 异常过滤器:Nest.js 的异常处理工具
介绍
欢迎回来!在前几篇文章中,我们已经了解了如何创建控制器、服务、中间件和管道,并使用它们来处理 HTTP 请求。在这篇文章中,我们将探讨 Nest.js 中的异常过滤器(Exception Filters)。异常过滤器是处理应用中异常情况的强大工具,可以捕获和处理异常,并返回自定义的响应。让我们一起深入了解异常过滤器的工作原理和使用方法。
什么是异常过滤器?
异常过滤器是一个类,它实现了 ExceptionFilter
接口,并包含一个 catch
方法。catch
方法接收两个参数:异常对象和当前的请求上下文。异常过滤器可以用于捕获和处理应用中的异常,并返回自定义的响应。
创建一个异常过滤器
让我们通过一个实际例子来了解如何创建和使用异常过滤器。假设我们要创建一个全局异常过滤器,用于捕获所有未处理的异常,并返回统一的错误响应。
首先,使用 Nest CLI 创建一个新的异常过滤器:
nest generate filter all-exceptions
这条命令会在 src
目录下生成一个 all-exceptions.filter.ts
文件。让我们看看这个文件的内容:
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception instanceof HttpException ? exception.getStatus() : 500;
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
@Catch()
:将类标记为异常过滤器。catch
方法:异常过滤器的核心方法,接收异常对象和当前的请求上下文。
使用异常过滤器
要使用异常过滤器,我们需要将其应用到特定的控制器或全局范围内。让我们将 AllExceptionsFilter
注册为全局异常过滤器。
打开 main.ts
文件,修改如下:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AllExceptionsFilter } from './all-exceptions.filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new AllExceptionsFilter());
await app.listen(3000);
}
bootstrap();
在这个例子中,我们使用 app.useGlobalFilters
方法将 AllExceptionsFilter
注册为全局异常过滤器。这样,所有未处理的异常都会被 AllExceptionsFilter
捕获并处理。
自定义异常响应
让我们修改 AllExceptionsFilter
,返回更详细的错误响应,包括错误信息和堆栈跟踪(仅在开发环境中)。
修改 all-exceptions.filter.ts
文件如下:
import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
import { Request, Response } from 'express';
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;
const errorResponse = {
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
message: exception instanceof HttpException ? exception.getResponse() : 'Internal server error',
};
if (process.env.NODE_ENV !== 'production') {
errorResponse['stack'] = exception instanceof Error ? exception.stack : null;
}
response.status(status).json(errorResponse);
}
}
在这个例子中,我们返回了更详细的错误响应,包括错误信息和堆栈跟踪(仅在开发环境中)。
捕获特定异常
有时,我们可能只想捕获特定类型的异常。我们可以使用 @Catch
装饰器指定要捕获的异常类型。
让我们创建一个新的异常过滤器,用于捕获 HttpException
类型的异常。
首先,使用 Nest CLI 创建一个新的异常过滤器:
nest generate filter http-exception
然后,修改 http-exception.filter.ts
文件如下:
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';
@Catch(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,
message: exception.getResponse(),
});
}
}
在这个例子中,我们使用 @Catch(HttpException)
装饰器指定要捕获的异常类型为 HttpException
。
要使用这个异常过滤器,我们可以将其应用到特定的控制器或全局范围内。让我们将 HttpExceptionFilter
应用到 BooksController
。
打开 books.controller.ts
文件,修改如下:
import { Controller, Get, Post, Put, Delete, Param, Body, UseFilters } from '@nestjs/common';
import { BooksService } from './books.service';
import { CreateBookDto } from './create-book.dto';
import { HttpExceptionFilter } from './http-exception.filter';
@Controller('books')
@UseFilters(HttpExceptionFilter)
export class BooksController {
constructor(private readonly booksService: BooksService) {}
@Get()
findAll(): string {
return this.booksService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string): string {
return this.booksService.findOne(id);
}
@Post()
create(@Body() createBookDto: CreateBookDto): string {
return this.booksService.create(createBookDto);
}
@Put(':id')
update(@Param('id') id: string, @Body() updateBookDto: CreateBookDto): string {
return this.booksService.update(id, updateBookDto);
}
@Delete(':id')
remove(@Param('id') id: string): string {
return this.booksService.remove(id);
}
}
在这个例子中,我们使用 @UseFilters
装饰器将 HttpExceptionFilter
应用到 BooksController
。每次 BooksController
中的方法抛出 HttpException
时,都会被 HttpExceptionFilter
捕获并处理。
结论
在这篇文章中,我们深入探讨了 Nest.js 中的异常过滤器,并通过实际例子展示了如何创建和使用异常过滤器。我们还学习了如何将异常过滤器应用到特定的控制器或全局范围内,以及如何捕获和处理特定类型的异常。
异常过滤器是处理应用中异常情况的强大工具,可以捕获和处理异常,并返回自定义的响应。通过使用异常过滤器,我们可以确保应用在异常情况下的行为更加一致和可控。
感谢你的阅读!如果你有任何问题或建议,欢迎在评论区留言。我们下次再见!
预告
在下一篇文章中,我们将探讨 Nest.js 中的守卫(Guards)。守卫是处理请求授权的强大工具,可以在请求到达控制器之前检查用户的权限。敬请期待!