filters
工欲善其事必先利其器,在更多功能,或者更多业务之前,我觉得很多服务端的设施应该先行一步,比如全局的错误拦截。
nest.js 本身内置了很多系统异常类,如果希望抛出异常,可以直接通过throw new xxx()
,需要注意的是,不同的异常类会抛出不同的状态码
BadRequestException — 400
UnauthorizedException — 401
ForbiddenException — 403
NotFoundException — 404
NotAcceptableException — 406
RequestTimeoutException — 408
ConflictException — 409
GoneException — 410
PayloadTooLargeException — 413
UnsupportedMediaTypeException — 415
UnprocessableEntityException — 422
InternalServerErrorException — 500
NotImplementedException — 501
BadGatewayException — 502
ServiceUnavailableException — 503
GatewayTimeoutException — 504
自定义异常过滤器
显然,虽然内置了不少异常处理,但并不足以面对我们日渐复杂的业务系统,因此,我们有必要实现 ExceptionFilter 接口来自定义我们的异常处理
先看使用方式
- 路由
import { Controller, Get, UseFilters } from '@nestjs/common';
import { HttpExceptionFilter } from 'src/common/filters/http-exception.filter';
import { UserService } from './user.service';
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService)
@Get()
@UseFilters(HttpExceptionFilter)
async getList() {
}
}
- 控制器
user.controller.ts
import { Controller, Get, UseFilters } from "@nestjs/common";
import { HttpExceptionFilter } from "src/common/filters/http-exception.filter";
import { UserService } from "./user.service";
@Controller("user")
@UseFilters(HttpExceptionFilter) //UseFilters装饰器使用
export class UserController {
// other
}
- 全局
main.ts 本例以全局使用为例
// 全局基础URL,届时所有路由前都会有这个基础的url
// app.setGlobalPrefix(AppModule.bsUrl);
// 全局注册错误的过滤器
app.useGlobalFilters(new HttpExceptionFilter());
// await app.listen....
新建\common\filters\http-exception.filter.ts
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
HttpStatus,
} from "@nestjs/common";
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
// 以下根据自己业务进行调整
// 错误码
// 此处给默认的状态码默认加了2位,自定义的状态码不必在意,只是想跟http状态码有个区分
let code = exception.getStatus();
code = Number(code + "00");
const message = exception.message;
const url = request.originalUrl;
const timestamp = new Date().toISOString();
// 整理返回全部的错误信息
const errorResponse = {
message, // 错误提示
result: [], // 默认结果为空数组
code, // 自定义code
timestamp,
url, // 错误的url地址
};
// http状态码响应,没有就是500
const status =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
// 设置返回的状态码、请求头、发送错误信息
response.status(status);
response.header("Content-Type", "application/json; charset=utf-8");
response.send(errorResponse);
}
}
访问路由
总结
自此,我们已经简单的实现了一个全局异常过滤器,可以对异常进行自定义处理,但可以看到,发生错误就错误了,作为开发者的我们并不清楚发生了什么错误,我们并没有进行日志收集,日志有利于我们排查问题,因此,后续我们还将实现日志的收集。