Nest错误异常处理

内置的异常层负责处理整个应用程序中的所有抛出的异常。

当捕获到未处理的异常时,最终用户将收到友好的响应。

Nest错误异常处理

官方文档

NestJS提供了一波拿来即用的内置异常过滤器;在@nestjs/common里面,搜索下Exception就有~,这里就是简单的说明如何做一些处理并包裹返回信息;

1. Nest内置的HttpStatus常用状态码定义

enum HttpStatus {
    OK = 200, //成功响应
    CREATED = 201, // 该请求已成功,并因此创建了一个新的资源。这通常是在POST请求,或是某些PUT请求之后返回的响应。
    ACCEPTED = 202,// 请求已经接收到,但还未响应,没有结果
    PARTIAL_CONTENT = 206, // 服务器已经成功处理了部分 GET 请求。类似于 FlashGet 或者迅雷这类的 HTTP 下载工具都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载。该请求必须包含 Range 头信息来指示客户端希望得到的内容范围,并且可能包含 If-Range 来作为请求条件。
    AMBIGUOUS = 300, // 被请求的资源有一系列可供选择的回馈信息,每个都有自己特定的地址和浏览器驱动的商议信息。用户或浏览器能够自行选择一个首选的地址进行重定向。
    MOVED_PERMANENTLY = 301, //被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一
    FOUND = 302,// 请求的资源现在临时从不同的 URI 响应请求。
    SEE_OTHER = 303,// 对应当前请求的响应可以在另一个 URI 上被找到,而且客户端应当采用 GET 的方式访问那个资源。
    NOT_MODIFIED = 304, // 如果客户端发送了一个带条件的 GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个状态码。
    BAD_REQUEST = 400, // 语义有误,当前请求无法被服务器理解;请求参数有误。
    UNAUTHORIZED = 401,// 当前请求需要用户验证。
    FORBIDDEN = 403,// 服务器已经理解请求,但是拒绝执行它。
    NOT_FOUND = 404,// 请求失败,请求所希望得到的资源未被在服务器上发现。
    METHOD_NOT_ALLOWED = 405,// 请求行中指定的请求方法不能被用于请求相应的资源
    PROXY_AUTHENTICATION_REQUIRED = 407, //与401响应类似,只不过客户端必须在代理服务器上进行身份验证。
    REQUEST_TIMEOUT = 408,// 请求超时
    CONFLICT = 409,// 由于和被请求的资源的当前状态之间存在冲突,请求无法完成。
    INTERNAL_SERVER_ERROR = 500, // 服务器遇到了不知道如何处理的情况。
    NOT_IMPLEMENTED = 501,// 此请求方法不被服务器支持且无法被处理。
    BAD_GATEWAY = 502,// 此错误响应表明服务器作为网关需要得到一个处理这个请求的响应,但是得到一个错误的响应。
    SERVICE_UNAVAILABLE = 503,// 服务器没有准备好处理请求。 
    GATEWAY_TIMEOUT = 504,// 当服务器作为网关,不能及时得到响应时返回此错误代码。
    HTTP_VERSION_NOT_SUPPORTED = 505 // 服务器不支持请求中所使用的HTTP协议版本。
}
复制代码

其实也就是规范中语义化显示状态码,文档

2. 建立异常处理过滤器

2.1 基础异常类/异常过滤

HttpException 这个就是nestjs 提供的基础异常类,自定义异常的时候,可以继承这个类,对异常进行改写.

不过一般来说,处理异常还是使用异常过滤器比较方便。什么是异常过滤器呢?其实就是对请求的响应,请求等方便进行一个再包装过滤处理。例如,我需要建立一个通用的异常处理返回机制,创建一个http-exception.filter.ts异常过滤器文件

先使用内置的命令行创建文件,nest g f common/filters/http-exception

异常过滤的几个步骤和一般来说需要捕获的参数:

  1. @nestjs/common包中导出Catch类装饰器
  2. 创建一个异常过滤器,实现ExceptionFilter
  3. 捕获请求上下文、请求上下文中的request对象、请求上下文中的response对象、异常状态码

下面就是一个异常过滤器的一个实现设计:

import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus, Logger } from '@nestjs/common';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  // 如果有日志服务,可以在constructor,中挂载logger处理函数
  constructor(private readonly logger: Logger) {}
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp(); // 获取请求上下文
    const request = ctx.getRequest(); // 获取请求上下文中的request对象
    const response = ctx.getResponse(); // 获取请求上下文中的response对象
    const status = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR; // 获取异常状态码
    // 设置错误信息
    const message = exception.message
      ? exception.message
      : `${status >= 500 ? '服务器错误(Service Error)' : '客户端错误(Client Error)'}`;

    const nowTime = new Date().getTime();

    const errorResponse = {
      data: {},
      message,
      code: -1,
      date: nowTime,
      path: request.url,
    };
    // 将异常记录到logger中
    this.logger.error(
      `【${nowTime}${request.method} ${request.url} query:${JSON.stringify(request.query)} params:${JSON.stringify(
        request.params,
      )} body:${JSON.stringify(request.body)}`,
      JSON.stringify(errorResponse),
      'HttpExceptionFilter',
    );
    // 设置返回的状态码, 请求头,发送错误信息
    response.status(status);
    response.header('Content-Type', 'application/json; charset=utf-8');
    response.send(errorResponse);
  }
}
复制代码

上面的就是一个对网络异常进行一个再包装(status状态非2xx),这样我们就将一个错误类型按照我们的期望做了一个通用返回处理,并且将异常加入到了日志,方便复现和查找原因

  1. 绑定过滤器,推荐全局绑定,在main.tsapp.useGlobalFilters(new HttpExceptionFilter(new Logger()));

补充:implementsextends的定位

  • implement 顾名思义,实现,一个新的类,从父类或者接口实现所有的属性和方法,同时可以重写属性和方法,包含一些新的功能
  • extends 顾名思义,继承,一个新的接口或者类,从父类或者接口继承所有的属性和方法,不可以重写属性,但可以重写方法
  • 接口不能实现接口或者类,所以实现只能用于类身上,即类可以实现接口或类
  • 接口可以继承接口或类
  • 类不可以继承接口,类只能继承类
  • 可多继承或者多实现

3. 拦截成功的返回数据

实现这个功能,使用的是nestjs中的拦截器,创建拦截器模板文件命令是nest g interceptor core/interceptor/transform

3.1 拦截器核心点

  • intercept() 方法,接受2个参数,一个是ExecutionContext,一个是CallHandler
  • ExecutionContext 继承自 ArgumentsHost
  • CallHandler,如果不手动调用 handle() 方法,则主处理程序根本不会进行求值
  • 绑定拦截器,可以选择在控制器范围,不过一般选择是在全局范围main.ts

3.2 实现对成功响应的拦截

import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { map, Observable } from 'rxjs';

@Injectable()
export class TransformInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(
      map((data) => {
        return {
          data,
          code: 0,
          msg: '请求成功',
        };
      }),
    );
  }
}
复制代码

总结:

对nest的异常错误处理,主要就是nest2个方面的东西

  • 异常过滤器
  • 拦截器

Guess you like

Origin juejin.im/post/7054082417736286244