Exception Filter
封装统一的 Exception Filter
Exception Filter 是在 Nest 应用抛异常的时候,捕获它并返回一个对应的响应。
Nest 给我们定义了很多 Exception,例如 HttpException,以及它的更多子 Exception:
- BadRequestException
- ForbiddenException
- ...等等。
比较通用的是 HttpException,基于它我们可以指定想要的 error 信息以及状态码等。
typescript1throw new HttpException('Forbidden', HttpStatus.FORBIDDEN)
如果我们不想要内置的 Exception Filter,想要自己处理 error 返回信息、状态码以及做更多的操作则可以自定义一个 Filter。
bash1nest generate filter CustomError --no-spec
typescript1import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common' 2 3@Catch() 4export class CustomErrorFilter<T> implements ExceptionFilter { 5 catch(exception: T, host: ArgumentsHost) {} 6}
@Catch装饰器可以指定需要捕捉的 Exception。
在这里我直接就指定需要捕捉 HttpException 错误(也可以不指定)。
typescript1@Catch(HttpException) 2export class CustomErrorFilter implements ExceptionFilter { 3 catch(exception: HttpException, host: ArgumentsHost) {} 4}
接着在 Controller 中抛出一个错误:
typescript1throw new BadRequestException('xxxxx')
然后再在CustomErrorFilter中打断点看一下抛出的错误:

我们抛出的 message 跟默认的 error 信息和 statusCode 都在 exception 中被捕获到了。
这里只需要用 response 对象返回信息给前端即可:
typescript1@Catch(HttpException) 2export class CustomErrorFilter implements ExceptionFilter { 3 catch(exception: HttpException, host: ArgumentsHost) { 4 const ctx = host.switchToHttp() 5 const response = ctx.getResponse() 6 const res = exception.getResponse() 7 const statusCode = exception.getStatus() 8 if (typeof res === 'string') { 9 response.status(statusCode).json({ 10 url: ctx.getRequest().url, 11 message: res, 12 error: exception.name, 13 statusCode: exception.getStatus(), 14 }) 15 } else { 16 response.status(statusCode).json({ 17 url: ctx.getRequest().url, 18 ...res, 19 }) 20 } 21 } 22}
如果想要在 Controller 中使用 Filter 就使用@UseFilters(CustomErrorFilter)装饰器。
如果想要 Global 使用,可以使用 APP_FILTER token 或者 app.useGlobalFilters()方法。
现在所有 HttpException 相关的错误信息都统一被处理掉了。
BadRequestException 返回信息:

Pipe 校验错误返回信息:

如果想要自定义 Exception,最好自继承 Nest 提供的 Exception。
下面是 BadRequestException 的源码,它就继承了 HttpException:
typescript1export declare class BadRequestException extends HttpException { 2 constructor(objectOrError?: string | object | any, descriptionOrOptions?: string | HttpExceptionOptions) 3}
总结
- 我们可以封装一个自定义的 Filter,通过 @Catch 指定要捕获的异常,然后在 catch 方法里拿到异常信息,返回对应的响应。
- 如果捕获的是 HttpException,要注意兼容 response 为 object 或者 string 的处理。
- filter 可以通过 @UseFilters 加在 handler 或者 controller 上,也可以在 main.ts 用 app.useGlobalFilters 全局启用。
- 如果 filter 要注入其他 provider,就要通过 AppModule 里注册一个 token 为 APP_FILTER 的 provider 的方式。
- 捕获的 Exception 可以自定义,最好继承自 Nest 提供的 Exception。