网络异常,图片无法展示
|
前言
正如官方所说:
内置的异常层负责处理整个应用程序中的所有抛出的异常。
当捕获到未处理的异常时,最终用户将收到友好的响应。
网络异常,图片无法展示
|
NestJS提供了一波拿来即用的内置异常过滤器;
在@nestjs/common
里面,搜索下Exception就有~
我们来一个具体的例子(全局异常过滤),
基于内置的异常过滤器实现,采用第三方日志(pino)记录异常日志,
做一些处理并包裹返回信息;
效果图
网络异常,图片无法展示
|
实战
# 基于cli生成filter模板 nest g f common/filters/http-exception
http-exception.filter.ts
// 日期格式化库,很小巧,类moment 风格api import * as dayjs from 'dayjs'; import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus, } from '@nestjs/common'; // nest默认底层是基于express封装,所以可以直接引入 import { Request, Response } from 'express'; // 第三方logger import { Logger } from 'nestjs-pino'; // 捕获请求异常类型 // 可以传递多个参数,所以你可以通过逗号分隔来为多个类型的异常设置过滤器。 @Catch(HttpException) export class HttpExceptionFilter implements ExceptionFilter { // 我们要把异常塞到自定义logger,必须引入对应的实例 // 在构建函数声明定义下,从外部传入 constructor(private readonly logger: Logger) {} catch(exception: HttpException, host: ArgumentsHost) { // 把请求相关的参数转成标准http的上下文 // 有兴趣可以点进去,GPRC,WEBSOCKET都能直接转换 // 也能直接拿到一些参数的及返回上下文类型 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 nowDate = dayjs(Date.now()).format('YYYY-MM-DDTHH:mm:ss'); // 包装异常信息 const errorResponse = { statusCode: status, message: exception.message, error: exception.name, date: nowDate, path: request.url, }; // 记录异常信息到第三方logger this.logger.error( `【${nowDate}】${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).json(errorResponse); } }
主入口(main.ts)
import { AppModule } from './app.module'; import { HttpExceptionFilter } from './common/filters/http-exception.filter'; import { Logger } from 'nestjs-pino'; import { NestFactory } from '@nestjs/core'; async function bootstrap() { const app = await NestFactory.create(AppModule, { cors: false, logger: false, }); // 获取pino logger实例 const logger = app.get(Logger); // nestjs-pino 取代nest logger app.useLogger(logger); // 设置全局异常过滤器 app.useGlobalFilters(new HttpExceptionFilter(logger)); await app.listen(configService.get('SERVE_LISTENER_PORT')); } bootstrap()
app.module.ts
若是只要特定模块生效可以使用Providers去实现,从核心模块导出;
import { Module } from '@nestjs/common'; // 包括网关,拦截器都可以走这种模式! import { APP_FILTER } from '@nestjs/core'; import { HttpExceptionFilter } from './common/filters/http-exception.filter'; @Module({ providers: [ { provide: APP_FILTER, useClass: HttpExceptionFilter, }, ], }) export class AppModule {}
若是加上@Global
装饰器也能达到全局模块的效果!
这个东东一般不推荐用在app.module,而是你需要导出的复用模块!
这里只是演示写法
import { Module,Global } from '@nestjs/common'; import { APP_FILTER } from '@nestjs/core'; @Global() @Module({ providers: [ { provide: APP_FILTER, useClass: HttpExceptionFilter, }, ], }) export class AppModule {}
@Global()
推荐用于给外部复用,又需要变成全局模块的,比如
import { Module, Global } from '@nestjs/common'; import { CatsController } from './cats.controller'; import { CatsService } from './cats.service'; @Global() @Module({ controllers: [CatsController], providers: [CatsService], exports: [CatsService], }) export class CatsModule {}