统一的异常处理器
有时候前端会进行一些错误的请求,这时候我们需要返回给他一个异常告知他的请求有问题,我们可以使用 NestJS 内置的异常处理HttpException
比如
throw new HttpException('您无权登录', HttpStatus.FORBIDDEN);
客户端就会收到
{ "statusCode": 403, "message": "您无权登录" }
但是这样不够灵活,所以我们可以新建一个异常过滤器进行自定义的操作
nest g filter common/filter/http-exception
然后修改common/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({ code: status, timestamp: new Date().toISOString(), path: request.url, describe: exception.message, }); } }
最后在main.ts
中进行注册
import { NestFactory } from "@nestjs/core"; import { AppModule } from "./app.module"; import { HttpExceptionFilter } from "./common/filter/http-exception/http-exception.filter"; async function bootstrap() { const app = await NestFactory.create(AppModule); //看这里看这里看这里~ app.useGlobalFilters(new HttpExceptionFilter()); await app.listen(3000); } bootstrap();
在user.service.ts
的 findAll 测试一下
async findAll() { throw new HttpException('禁止访问', HttpStatus.FORBIDDEN); return await this.userRepository.find(); }
前端就会收到错误信息的返回
返回格式化拦截器
我们还需要一个返回格式的拦截器对请求成功(状态码为 2xx)的数据进行一个格式化,比如返回这样的格式
{ data:业务参数, code:状态码, describe:状态描述 ... }
同样的先执行
nest g interceptor common/interceptor/transform
创建一个拦截器,按照官网示例给的复制过来
import { Injectable, NestInterceptor, ExecutionContext, CallHandler, } from "@nestjs/common"; import { Observable } from "rxjs"; import { map } from "rxjs/operators"; export interface Response<T> { data: T; } @Injectable() export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> { intercept( context: ExecutionContext, next: CallHandler ): Observable<Response<T>> { return next .handle() .pipe(map((data) => ({ code: 200, data, describe: "请求成功" }))); } }
和过滤器一样在main.ts
中注册
import { NestFactory } from "@nestjs/core"; import { AppModule } from "./app.module"; import { HttpExceptionFilter } from "./common/filter/http-exception/http-exception.filter"; import { TransformInterceptor } from "./common/interceptor/transform/transform.interceptor"; async function bootstrap() { const app = await NestFactory.create(AppModule); //看这里看这里看这里~ app.useGlobalFilters(new HttpExceptionFilter()); app.useGlobalInterceptors(new TransformInterceptor()); await app.listen(3000); } bootstrap();
我们再将findAll
函数改为请求成功的状态
async findAll() { return await this.userRepository.find(); }
进行请求就会发现数据已经被格式化了
但是这样做之后我们会发现请求成功的 code 只能是 200,一般项目中请求成功还需要很多业务异常状态码返回给前端,所以我们需要新建一个抛出业务异常的类
ApiException
我们先创建common/enums/api-error-code.enum.ts
用于存放我们的业务状态码,这里简单写几个
export enum ApiErrorCode { SUCCESS = 200, // 成功 USER_ID_INVALID = 10001, // 用户id无效 USER_NOTEXIST = 10002, // 用户id无效 }
然后在http-exception
中新建api.exception.ts
,创建一个ApiException
类继承HttpException
,接受三个参数错误信息
,错误码code
,http状态码(默认是200)
import { HttpException, HttpStatus } from '@nestjs/common'; import { ApiErrorCode } from '../../enums/api-error-code.enum'; export class ApiException extends HttpException { private errorMessage: string; private errorCode: ApiErrorCode; constructor( errorMessage: string, errorCode: ApiErrorCode, statusCode: HttpStatus = HttpStatus.OK, ) { super(errorMessage, statusCode); this.errorMessage = errorMessage; this.errorCode = errorCode; } getErrorCode(): ApiErrorCode { return this.errorCode; } getErrorMessage(): string { return this.errorMessage; } }
然后修改http-exception.filter.ts
,可以判断exception是否在ApiException
原型链上来确定是调用的是ApiException
还是HttpException
import { ExceptionFilter, Catch, ArgumentsHost, HttpException, } from '@nestjs/common'; import { Request, Response } from 'express'; import { ApiException } from './api.exception'; @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(); if (exception instanceof ApiException) { response.status(status).json({ code: exception.getErrorCode(), timestamp: new Date().toISOString(), path: request.url, describe: exception.getErrorMessage(), }); return; } response.status(status).json({ code: status, timestamp: new Date().toISOString(), path: request.url, describe: exception.message, }); } }
然后在 findAll 函数中抛出一个业务异常
async findAll() { throw new ApiException('用户不存在', ApiErrorCode.USER_NOTEXIST); return await this.userRepository.find(); }
然后进行请求
此时你会发现请求是成功的,但是 code 值是异常的,符合我们的预期
到这里NestJS的基本配置已经做完了,后续便可直接开始我们业务的开发了,欢迎点赞收藏加关注!