egg-validate 基于 parameter 的 eggjs 字段验证模块

发布于 2020-04-21 15:32:47 字数 7349 浏览 4797 评论 0

egg-validate 是基于 parameter 的 eggjs 字段验证模块,可以验证我们日常开发中的大多数字段类型和数据,如果插件不满足你的需求,你还可以自定义验证规则。

安装

npm install --save egg-validate

启用

// config/plugin.js
exports.validate = {
  enable: true,
  package: 'egg-validate',
};

配置

// config/config.default.js
exports.validate = {
  // convert: false,
  // validateRoot: false,
};

使用方法

egg-validate 就是对参数进行检验。比如检验一个用户名是不是字符串,可以这么写:

ctx.validate({ userName: 'string' });

默认就会对 ctx.request.body 进行检验,你想检验 ctx.query 的话,那就这样写:

ctx.validate({ userName: 'string' }, ctx.query);

params 就 ctx.params,它会在检验失败的抛出一个异常,没有捕获的话,会返回一个 422 错误。

第二种使用方法:

let errs = app.validator.validate({ userName: 'string' }, ctx.request.body);

ctx.validate 检验不通过会抛出异常,而 app.validator.validate 检验不通过会返回错误。你可以自己选择要对这个错误怎么处理,是停止执行还是返回前端。

完整的代码

// app/controller/home.js
const Controller = require('egg').Controller;
class HomeController extends Controller {
  async index() {
    const { ctx, app } = this;
    ctx.validate({ id: 'id' }); // will throw if invalid
    // or
    const errors = app.validator.validate({ id: 'id' }, ctx.request.body);
  }
}
module.exports = HomeController;

校验规则 rule

完全和 parameter 的校验规则一样。建议直接看readme文档,虽然是英文的,但是配着翻译看个7788是差不多的。

ctx.validate({ userName: 'string' });

这里面的rule就是{ userName: 'string' },它会这么检验,首先判断这个userName有没有在ctx.request.body里面,没有就跑出参数不存在、然后是userName不能为空、然后得是string。有一个不符合都会抛出错误。

你想判断一个用户的信息是否正确可以这么写:

ctx.validate({
  userName: 'userName',	        // 自定义的校验规则
  password: 'password',	        // 自带的校验规则
  sex: ['men', 'women'],	// 性别是 men 或者 women
  age: {
    type: 'number',		// 年龄范围0-120
    min: 0,
    max: 120
  }
});

这里有个坑,年龄怎么填都会报格式错误,这是因为配置的时候默认把参数转型关了,配置回来就好:

config.validate = {   // 配置参数校验器,基于parameter
  convert: true,      // 对参数可以使用 convertType 规则进行类型转换
  // validateRoot: false,   // 限制被验证值必须是一个对象。
};

使用自带的校验规则

password: 'password'

或者

password: {
  type: 'password',
  allowEmpty: true	// 设置密码为空,作为示例乱写一下
}

校验规则有这些,文档很详细了:

  • 'int' => {type: 'int', required: true}
  • 'int?' => {type: 'int', required: false }
  • 'integer' => {type: 'integer', required: true}
  • 'number' => {type: 'number', required: true}
  • 'date' => {type: 'date', required: true}
  • 'dateTime' => {type: 'dateTime', required: true}
  • 'id' => {type: 'id', required: true}
  • 'boolean' => {type: 'boolean', required: true}
  • 'bool' => {type: 'bool', required: true}
  • 'string' => {type: 'string', required: true, allowEmpty: false}
  • 'string?' => {type: 'string', required: false, allowEmpty: true}
  • 'email' => {type: 'email', required: true, allowEmpty: false, format: EMAIL_RE}
  • 'password' => {type: 'password', required: true, allowEmpty: false, format: PASSWORD_RE, min: 6}
  • 'object' => {type: 'object', required: true}
  • 'array' => {type: 'array', required: true}
  • [1, 2] => {type: 'enum', values: [1, 2]}
  • /\d+/ => {type: 'string', required: true, allowEmpty: false, format: /\d+/}

自定义的校验规则

通过 app.validator.addRule 添加:

// 校验用户名是否正确
app.validator.addRule('userName', (rule, value)=>{		// value就是待检验的数据
  if (/^\d+$/.test(value)) {
    return "用户名应该是字符串";
  }
  else if (value.length < 3 || value.length > 10) {
    console.log("用户名的长度应该在3-10之间");
  }
});

这个可以直接放在 app.js 里面。return 的就是错误消息 message,但是 err 不止这个,还有错误字段啊啥的、都会帮我们自动包装好。

添加了这个规则就可以直接使用:

ctx.validate({userName: 'userName'});

或者这样使用:

ctx.validate({
  userName: {
    type: 'userName',
    isAdmin: true'
  },
});

直接赋值给 rule 传过来,然后你可以自己加判断,比如如果 isAdmin 的话,管理员用户名不能有中文啥的。

在哪里 addRule

上面写的是推荐大家在 app.js 里面 addRule,你可以在任何你能取到 app 的地方调用

app.validator.addRule('userName', (rule, value)=>{

去 addRule,但是不建议在 controller 里面 addRule。因为 controller 在每次路由匹配到之后都会进行实例化,所以请求了 n 遍,也就执行了这个 addRule n 遍。

而且代码会变的很臃肿,不易于管理。

在 app.js addRule 当然是很棒的,只在 app 加载时 add 一次。

但是问题又来了,随着 rule 变多,你在 app.js 里面写了很多代码都是关于 addRule 的,但是 app.js 又不止要写addRule,还写了一些别的,那看起来多乱啊。也不利于管理。

如何合理配置文件目录

我们希望能达到怎么样的一个效果呢?

  1. app.js 里面少写一些代码,最好就写一两行,做个配置这样子
  2. 对于所有的自定义校验规则独立出文件夹,取名 validate,放在 app/ 下面
  3. 针对相似的校验规则进一步抽象成文件,取名 user.js,放在 app/validate/ 下面
  4. 针对某一条特定的校验规则,如校验用户的 userName 放在 app/validate/user.js 里面
  5. 然后保持 egg-validate 的使用规则不变,原来是 ctx.validate 现在还是 ctx.vallidate。同时其他的插件、配置不受影响。

下面照着这几个目标实现代码

首先把 app.js 里面导入模块写出来

我们使用 Loader 来加载 validate 下面的所有文件:

const path = require('path');

module.exports = app => {

  // 你的其它代码,balabala

  // 加载所有的校验规则
  const directory = path.join(app.config.baseDir, 'app/validate');
  app.loader.loadToApp(directory, 'validate');
}

建立实际的校验规则文件

建立 app/validate/user.js 文件,写入以下代码

// app/validate/user.js
module.exports = app =>{

  let { validator } = app;

  // 校验用户名是否正确
  validator.addRule('userName', (rule, value)=>{
    console.log(rule);
    if (/^\d+$/.test(value)) {
      return "用户名应该是字符串";
    }
    else if (value.length < 3 || value.length > 10) {
      console.log("用户名的长度应该在3-10之间");
    }
  });

  // 添加自定义参数校验规则
  validator.addRule('123', (rule, value) => {
    if (value !== '123'){
      return 'must be 123';
    }
  });
};

这里validator.addRule和原来一样,只是为了少写代码,之前把 validator 取出来了:

let { validator } = app;

之后需要再新建检验规则就写在 validate 里面,某一类相似校验规则要复用就直接拷贝文件就好了。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84959 人气
更多

推荐作者

yangzhenyu123

文章 0 评论 0

lvzun

文章 0 评论 0

执笔绘流年

文章 0 评论 0

芯好空

文章 0 评论 0

始于初秋

文章 0 评论 0

谁与争疯

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文