nestjs入门学习 | day4

发布时间 2023-07-13 23:36:30作者: fozero

nestjs入门学习 | day4

day4:

  • 接口格式统一
  • 请求参数验证

接口格式统一

  • 请求成功返回
{
    "code": 0,
    "message": "OK",
    "data": []
}
  • 请求失败返回
{
    "code": -1,
    "message": "error reason",
    "data": null
}

请求成功返回

这里我们借助拦截器来实现

使用命令创建一个拦截器

nest g interceptor transform
import {
  CallHandler,
  ExecutionContext,
  Injectable,
  NestInterceptor,
} from '@nestjs/common';
import { Observable, map } 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: '请求成功',
        };
      }),
    );
  }
}

handle() 返回一个 Observable。此流包含从路由处理程序返回的值, 因此我们可以使用 map() 运算符轻松地对其进行改变。

全局注册我们刚创建好的拦截器

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { TransformInterceptor } from './core/interceptor/transform.interceptor';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  // 全局注册拦截器
  app.useGlobalInterceptors(new TransformInterceptor());
  await app.listen(3000);
}
bootstrap();

请求失败返回

使用命令创建一个异常过滤器

nest g filter http-exception

创建好后,实现HttpExceptionFilter,捕获作为HttpException类实例的异常,并为它们设置自定义响应逻辑。

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

/**
 * 异常过滤器 异常返回统一响应
 * 捕获作为HttpException类实例的异常,并为它们设置自定义响应逻辑
 */
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    // 获取请求上下文
    const ctx = host.switchToHttp();
    // 获取请求上下文中的 response对象
    const response = ctx.getResponse();
    // 获取异常状态码
    const status = exception.getStatus();
    // 异常消息
    const message = exception.message ? exception.message : 'Service Error';
    // Response.json()方法,使用 Response对象直接控制发送的响应。
    response.status(status).json({
      code: -1,
      message: message,
      data: null,
    });
  }
}

全局注册异常过滤器

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpExceptionFilter } from './core/filter/http-exception.filter';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  // 全局注册异常过滤器
  app.useGlobalFilters(new HttpExceptionFilter());
  await app.listen(3000);
}
bootstrap();

抛出异常,在service中使用并抛出异常

import { HttpException, HttpStatus } from '@nestjs/common';

async findAll() {
    throw new HttpException('获取数据失败', HttpStatus.BAD_REQUEST);
}

HttpException 构造函数有两个必要的参数来决定响应:

  • response 参数定义 JSON 响应体。它可以是 string 或 object

  • status参数定义HTTP状态代码。

仅覆盖 JSON 响应主体的消息部分,请在 response参数中提供一个 string。

要覆盖整个 JSON 响应主体,请在response 参数中传递一个object。 Nest将序列化对象,并将其作为JSON 响应返回。

第二个构造函数参数-status-是有效的 HTTP 状态代码。 最佳实践是使用从@nestjs/common导入的 HttpStatus枚举。

以下是几个常见的状态枚举值

HttpStatus.BAD_REQUEST
HttpStatus.FORBIDDEN
HttpStatus.INTERNAL_SERVER_ERROR

为了方便,Nest 提供了一系列继承自核心异常 HttpException 的可用异常

BadRequestException
UnauthorizedException
NotFoundException
ForbiddenException
NotAcceptableException
RequestTimeoutException
ConflictException
GoneException
PayloadTooLargeException
UnsupportedMediaTypeException
UnprocessableException
InternalServerErrorException
NotImplementedException
BadGatewayException
ServiceUnavailableException
GatewayTimeoutException

HttpStatus和HttpException异常都来自@nestjs/common包中

修改之前的,我们直接使用BadRequestException来抛出异常

// 之前方式
async findAll() {
    throw new HttpException('获取数据失败', HttpStatus.BAD_REQUEST);
}

// 现在方式
async findAll() {
    throw new BadRequestException('获取数据失败');
}

请求参数验证

Nest自带九个开箱即用的管道,他们从 @nestjs/common 包中导出

ValidationPipe
ParseIntPipe
ParseFloatPipe
ParseBoolPipe
ParseArrayPipe
ParseUUIDPipe
ParseEnumPipe
DefaultValuePipe
ParseFilePipe

其中ValidationPipe 配合class-validator就可以完美的实现我们想要的效果(对参数类型进行验证,验证失败抛出异常)。

管道验证操作通常用在dto这种传输层的文件中,用作验证操作。首先我们安装两个需要的依赖包:class-transformer和class-validator

  1. 安装相关库
yarn add class-validator class-transformer
  1. 在dto中添加验证和错误提示信息

更多关于class-validator的用法,可以查看阅读官方文档https://github.com/typestack/class-validator#validation-messages

import { IsString, IsNotEmpty } from 'class-validator';

/**
 * 请求参数验证
 */
export class CreateLinkDto {
  @IsString()
  @IsNotEmpty({ message: '请输入链接名称' })
  readonly name: string;

  @IsString()
  @IsNotEmpty({ message: '请输入链接地址' })
  readonly url: string;
}
  1. 修改异常过滤器,补充增加对object类型情况的判断
import {
  ArgumentsHost,
  Catch,
  ExceptionFilter,
  HttpException,
} from '@nestjs/common';

/**
 * 异常过滤器 异常返回统一响应
 * 捕获作为HttpException类实例的异常,并为它们设置自定义响应逻辑
 */
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    // 获取请求上下文
    const ctx = host.switchToHttp();
    // 获取请求上下文中的 response对象
    const response = ctx.getResponse();
    // 获取异常状态码
    const status = exception.getStatus();

    let validMessage = '';
    // exceptionResponse返回结果格式: { message: [ '请输入链接名称' ], error: 'Bad Request', statusCode: 400 }
    // exceptionResponse {
    //   message: [ 'name must be a string', '请输入链接名称' ],
    //   error: 'Bad Request',
    //   statusCode: 400
    // }
    const exceptionResponse: any = exception.getResponse();
    // 考虑异常返回object类型的请求
    if (typeof exceptionResponse === 'object') {
      validMessage =
        typeof exceptionResponse.message === 'string'
          ? exceptionResponse.message
          : exceptionResponse.message[0];
    }

    // 异常消息
    const message = exception.message ? exception.message : 'Service Error';
    // Response.json()方法,使用 Response对象直接控制发送的响应。
    response.status(status).json({
      code: -1,
      message: validMessage || message,
      data: null,
    });
  }
}
  1. 注册全局验证管道
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';

import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  // 全局注册验证管道
  app.useGlobalPipes(new ValidationPipe());
  await app.listen(3000);
}
bootstrap();
  1. 接下来请求接口进行测试
{
    "code": -1,
    "message": "请输入链接名称",
    "data": null
}

{
    "code": -1,
    "message": "name must be a string",
    "data": null
}

项目源码

代码已经上传到github中,欢迎大家star,持续更新,如有任何问题可以联系我v:sky201208(注明来意)

https://github.com/fozero/cloud-collect-nestjs

参考阅读

关于我&前端&node进阶交流学习群

大家好,我是阿健Kerry,一个有趣且乐于分享的人,前小鹏汽车、货拉拉高级前端工程师,长期专注前端开发,如果你对前端&Node.js 学习进阶感兴趣的话(后续有计划也可以),可以关注我,加我微信【sky201208】,拉你进交流群一起交流、学习共同进步,群内氛围特别好,定期会组织技术分享~