当前位置: 代码网 > it编程>编程语言>Javascript > NestJS使用class-validator进行数据验证

NestJS使用class-validator进行数据验证

2024年11月25日 Javascript 我要评论
前言在现代web开发中,数据验证是必不可少的一环,它不仅能够确保数据的准确性,还能提高系统的安全性。在使用nestjs框架进行项目开发时,class-validator与class-transform

前言

在现代web开发中,数据验证是必不可少的一环,它不仅能够确保数据的准确性,还能提高系统的安全性。在使用nestjs框架进行项目开发时,class-validator与class-transformer这两个库为我们提供了方便的数据验证解决方案。

本文将通过详细的步骤和实战技巧,带大家掌握如何在nestjs中使用class-validator进行数据验证。通过这篇文章,你将能够学会如何使用class-validator优雅的实现数据验证,以及11条实战中常用的验证技巧,提高项目的数据校验能力。

使用步骤

第一步:安装 class-validator 和 class-transformer

要使用 class-validator,需要安装两个库:class-validator 和 class-transformer。

npm install class-validator class-transformer

第二步:创建 dto(数据传输对象)

在 nestjs 中,通常使用 dto(data transfer object)来定义请求数据的结构。首先,需要创建一个用于用户注册的 dto 类,并使用 class-validator 的装饰器来定义验证规则。

// src/user/dto/create-user.dto.ts
import { isstring, isemail, isnotempty, length } from 'class-validator';

export class createuserdto {
  @isstring()
  @isnotempty()
  @length(4, 20)
  username: string;

  @isemail()
  email: string;

  @isstring()
  @isnotempty()
  @length(8, 40)
  password: string;
}

在这个 dto 中,定义了三个字段:username、email 和 password,并使用 class-validator 的装饰器指定了验证规则。

第三步:使用管道验证数据

接下来,需要在控制器中使用 dto,并通过 nestjs 的管道(pipes)来验证传入的数据。

// src/user/user.controller.ts
import { controller, post, body } from '@nestjs/common';
import { createuserdto } from './dto/create-user.dto';

@controller('user')
export class usercontroller {
  @post('register')
  async register(@body() createuserdto: createuserdto) {
    // 处理注册逻辑
    return { message: 'user registered successfully', data: createuserdto };
  }
}

在这个例子中,在 register 方法中使用了 @body() 装饰器来获取请求体,并传入了 createuserdto。nestjs 会自动验证该 dto,如果验证失败,将抛出异常并返回适当的错误响应。

第四步:全局启用验证管道

为了更方便地管理,可以全局启用验证管道,这样所有的 dto 验证都会自动进行。

// src/main.ts
import { validationpipe } from '@nestjs/common';
import { nestfactory } from '@nestjs/core';
import { appmodule } from './app.module';

async function bootstrap() {
  const app = await nestfactory.create(appmodule);
  app.useglobalpipes(new validationpipe());
  await app.listen(3000);
}

bootstrap();

在 main.ts 文件中,使用 validationpipe 全局启用了验证管道。这样一来,无论在哪个控制器中使用 dto,nestjs 都会自动进行数据验证。当然也可以仅对某些控制器开启验证管道,详情参考下方实战技巧。

实战使用技巧

1. 局部验证管道

可以为特定的路由或控制器方法配置验证管道,而无需全局启用。这样可以在不同的场景下灵活使用不同的验证规则。

import { controller, post, body, usepipes, validationpipe } from '@nestjs/common';
import { createuserdto } from './dto/create-user.dto';

@controller('user')
export class usercontroller {
  @post('register')
  @usepipes(new validationpipe({
    transform: true,
    whitelist: true,
    forbidnonwhitelisted: true,
  }))
  async register(@body() createuserdto: createuserdto) {
    // 处理注册逻辑
    return { message: 'user registered successfully', data: createuserdto };
  }
}

2. 自定义错误消息

class-validator 允许为每个验证规则定义自定义错误消息。例如:

import { isstring, isnotempty, length, isemail } from 'class-validator';

export class createuserdto {
  @isstring({ message: '用户名必须是字符串' })
  @isnotempty({ message: '用户名不能为空' })
  @length(4, 20, { message: '用户名长度必须在4到20个字符之间' })
  username: string;

  @isemail({}, { message: '邮箱格式不正确' })
  email: string;
  
  @isstring({ message: '密码必须是字符串' })
  @isnotempty({ message: '密码不能为空' })
  @length(8, 40, { message: '密码长度必须在8到40个字符之间' })
  password: string;
}

3. 嵌套对象验证

如果 dto 中包含嵌套对象,可以使用 @validatenested() 装饰器进行验证。例如:

import { type } from 'class-transformer';
import { validatenested, isstring, isnotempty } from 'class-validator';

class addressdto {
  @isstring()
  @isnotempty()
  street: string;

  @isstring()
  @isnotempty()
  city: string;
}

export class createuserdto {
  @isstring()
  @isnotempty()
  username: string;

  @validatenested()
  @type(() => addressdto)
  address: addressdto;
}

4. 组合验证装饰器

有时可能需要将多个验证规则组合在一起,这时可以使用 @validatorconstraint() 来创建自定义验证装饰器。例如:

判断数据库中是否已经存在用户名

import { registerdecorator, validationoptions, validatorconstraint, validatorconstraintinterface } from 'class-validator';

@validatorconstraint({ async: false })
export class isusernameuniqueconstraint implements validatorconstraintinterface {
  validate(username: any) {
    // 这里可以添加验证逻辑,例如查询数据库
    return true; // 如果验证通过返回 true
  }
}

export function isusernameunique(validationoptions?: validationoptions) {
  return function (object: object, propertyname: string) {
    registerdecorator({
      target: object.constructor,
      propertyname: propertyname,
      options: validationoptions,
      constraints: [],
      validator: isusernameuniqueconstraint,
    });
  };
}

// 使用自定义装饰器
export class createuserdto {
  @isusernameunique({ message: '用户名已存在' })
  username: string;
}

2.验证密码强度

import { registerdecorator, validationoptions, validationarguments } from 'class-validator';
export function isstrongpassword(validationoptions?: validationoptions) {
  return function (object: object, propertyname: string) {
    registerdecorator({
      name: 'isstrongpassword',
      target: object.constructor,
      propertyname: propertyname,
      options: validationoptions,
      validator: {
        validate(value: any, args: validationarguments) {
          return /(?=.*[a-z])(?=.*[a-z])(?=.*\d)(?=.*[@$!%*?&])[a-za-z\d@$!%*?&]{8,}/.test(value);
        },
        defaultmessage(args: validationarguments) {
          return '密码必须包含大小写字母、数字和特殊字符,并且至少8个字符长';
        },
      },
    });
  };
}
export class changepassworddto {
  @isstrongpassword({ message: '密码不符合强度要求' })
  newpassword: string;
}

3.条件验证

根据条件进行验证,可以使用 @validateif 装饰器。

import { validateif, isnotempty, isemail } from 'class-validator';
export class updateuserdto {
  @isemail()
  email: string;
  @validateif(o => o.email)
  @isnotempty({ message: '新邮件地址不能为空' })
  newemail: string;
}

4.使用 @matches 进行正则表达式验证

使用 @matches 装饰器,可以验证字符串是否与指定的正则表达式匹配。

import { matches } from 'class-validator';
export class changepassworddto {
  @matches(/(?=.*[a-z])(?=.*[a-z])(?=.*\d)(?=.*[@$!%*?&])[a-za-z\d@$!%*?&]{8,}/, { message: '密码必须包含大小写字母、数字和特殊字符,并且至少8个字符长' })
  newpassword: string;
}

5.全局验证选项

全局启用验证管道时,可以配置全局验证选项,比如剥离非白名单字段、自动转换类型等。

// src/main.ts
import { validationpipe } from '@nestjs/common';
import { nestfactory } from '@nestjs/core';
import { appmodule } from './app.module';
async function bootstrap() {
  const app = await nestfactory.create(appmodule);
  app.useglobalpipes(new validationpipe({
    whitelist: true, // 剥离非白名单字段
    forbidnonwhitelisted: true, // 禁止非白名单字段
    transform: true, // 自动转换类型
  }));
  await app.listen(3000);
}
bootstrap();

6.动态验证消息

有时可能需要根据具体的验证条件动态生成错误消息,可以使用 validationarguments 来实现。

import { isstring, minlength, validationarguments } from 'class-validator';

export class createuserdto {
  @isstring()
  @minlength(4, {
    message: (args: validationarguments) => {
      return `用户名太短了,至少需要 ${args.constraints[0]} 个字符`;
    },
  })
  username: string;
}

7.@validate 自定义验证逻辑

如果内置装饰器无法满足需求,可以使用 @validate 装饰器添加自定义验证逻辑。

import { validate, validatorconstraint, validatorconstraintinterface, validationarguments } from 'class-validator';

@validatorconstraint({ name: 'customtext', async: false })
class customtextconstraint implements validatorconstraintinterface {
  validate(text: string, args: validationarguments) {
    return text.startswith('prefix_'); // 任何自定义逻辑
  }

  defaultmessage(args: validationarguments) {
    return '文本 ($value) 必须以 "prefix_" 开头';
  }
}

export class customtextdto {
  @validate(customtextconstraint)
  customtext: string;
}

8.属性分组验证

通过分组,可以在不同情境下验证不同的字段。比如在创建和更新时可能需要验证不同的字段。

import { isstring, isnotempty } from 'class-validator';

export class createuserdto {
  @isstring()
  @isnotempty({ groups: ['create'] })
  username: string;

  @isstring()
  @isnotempty({ groups: ['create', 'update'] })
  password: string;
}

// 使用时指定组
import { validationpipe } from '@nestjs/common';

const createuservalidationpipe = new validationpipe({ groups: ['create'] });
const updateuservalidationpipe = new validationpipe({ groups: ['update'] });

在控制器中使用不同的管道进行验证:
import { controller, post, put, body, usepipes } from '@nestjs/common';
import { createuserdto } from './dto/create-user.dto';
import { createuservalidationpipe, updateuservalidationpipe } from './validation-pipes';

@controller('user')
export class usercontroller {
  @post('create')
  @usepipes(createuservalidationpipe)
  async createuser(@body() createuserdto: createuserdto) {
    // 处理创建用户逻辑
    return { message: 'user created successfully', data: createuserdto };
  }

  @put('update')
  @usepipes(updateuservalidationpipe)
  async updateuser(@body() updateuserdto: createuserdto) {
    // 处理更新用户逻辑
    return { message: 'user updated successfully', data: updateuserdto };
  }
}

9.仅执行部分属性验证

有时可能需要只验证对象的一部分属性,可以使用 partialtype 来实现。

import { partialtype } from '@nestjs/mapped-types';

export class updateuserdto extends partialtype(createuserdto) {}
//以下是如何在控制器中使用 updateuserdto。
// src/user/user.controller.ts
import { controller, post, put, body, param } from '@nestjs/common';
import { createuserdto } from './dto/create-user.dto';
import { updateuserdto } from './dto/update-user.dto';
@controller('user')
export class usercontroller {
  @post('create')
  async createuser(@body() createuserdto: createuserdto) {
    // 处理创建用户逻辑
    return { message: 'user created successfully', data: createuserdto };
  }
  @put('update/:id')
  async updateuser(@param('id') id: string, @body() updateuserdto: updateuserdto) {
    // 处理更新用户逻辑
    return { message: 'user updated successfully', data: updateuserdto };
  }
}

在这个示例中,updateuserdto 继承自 partialtype(createuserdto),这意味着 updateuserdto 包含 createuserdto 中的所有属性,但这些属性都是可选的。这在更新操作中非常有用,因为我们可能只想提供那些需要更新的字段,而不是所有字段。

10.验证消息的国际化

通过使用自定义验证装饰器和消息生成函数,可以实现验证消息的国际化。

import { isstring, isnotempty, length, validationarguments } from 'class-validator';
import { i18n } from 'i18next'; // 假设在项目中使用 i18n

export class createuserdto {
  @isstring()
  @isnotempty({ message: (args: validationarguments) => i18n.t('validation.usernamerequired') })
  @length(4, 20, { message: (args: validationarguments) => i18n.t('validation.usernamelength', { min: 4, max: 20 }) })
  username: string;
}

总结

使用 class-validator 结合 nestjs,可以让轻松地在应用中进行数据验证,不仅提高了代码的可读性,还保证了数据的准确性和安全性。

以上就是nestjs使用class-validator进行数据验证的详细内容,更多关于nestjs数据验证的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com