木灵鱼儿

木灵鱼儿

阅读:1158

最后更新:2021/03/13/ 23:47:42

koa教程2 用户注册及Joi校验、成功信息返回

用户注册

用户数据表搭建完毕后,我们肯定是需要注册用户的,那么首先我们需要创建一个路由api了。

在根目录:/app/router/v1目录下创建一个user.js文件。

user.js:

const Router = require("koa-router");
const router = new Router({ prefix: "/v1/user" });
const { User } = require(`${process.cwd()}/models/user`);



//注册用户
router.post("/register", async (ctx, next) => {

});


module.exports = router;

注意:记得在app.js中删除上一节require("./models/user")代码,因为已经不需要了,我们这这里使用了。

假设客户端传来的数据如下:ctx.body

{
  email: "1321968423@qq.com",
  password1: "123456",
  password2: "123456",
  nickname: "木灵鱼儿"
}

那么我们要对这个参数进行校验

参数校验

通过ctx.body我们可以拿到客户端传过来的数据。为此在校验前我们需要安装Joi

yarn add joi --dev

joi如何校验数据?

首先我们需要通过Joi.object()创建一个参数校验对象A,然后通过这个参数校验对象A的validateAsync方法,将ctx.body传入,然后joi就会根据我们的设定进行参数校验,不通过将会抛出Error错误对象。

成功,则是会返回被检验的参数,注意,这个参数可以在校验时改动,比如一个参数首尾代空格,我们可以通过joi将首尾空格去除,然后在存入数据库中。

joi默认是自动创建Error对象的,这个错误最终会被我们全局错误捕获所捕获,但是这个Error并没有我们需要参数,所以,我们需要控制joi的错误对象为我们自定义的错误对象才行,好在这个行为我们是可以控制的。

创建校验失败的错误对象

http-error.js:

//基础错误对象
class HttpError extends Error {
  constructor(msg = "服务器异常", errorCode = 10000, status = 400) {
    super();
    this.errorCode = errorCode;
    this.status = status;
    this.msg = msg;
  }
};

//校验不通过的错误对象
class ValidateError extends HttpError {
  constructor(msg, errorCode) {
    super();
    this.errorCode = errorCode || 10001;
    this.status = 200;
    this.msg = msg || "参数检验不通过!";
  }
};


module.exports = {
  HttpError,
  ValidateError,
};

ValidateError 将是我们参数校验不通过所使用的错误对象,他的状态是200,访问是成功地。

创建创建用户校验方法

在utils目录下,创建一个validate目录,里面用于存放我们校验的方法,在validate中创建user.js文件

user.js:

const Joi = require("joi");
const { ValidateError } = require(`${process.cwd()}/core/http-error`);
const { User } = require(`${process.cwd()}/models/user`);

//验证数据库是否已经有相同邮箱
const isExistSameEmail = async (email) => {
  const user = await User.findOne({
    where: { email }
  });
  //查不到返回null
  if (user) throw new ValidateError("邮箱已存在!");
  return email; //可以在这改变返回值
};

//注册账号
const registerValidate = (data) => {
  const joiObject = Joi.object({
    //最低2位邮箱@后面的内容,例:@io
    email: Joi.string().email({ minDomainSegments: 2 })
      .required().external(isExistSameEmail, "是否存在相同邮箱")
      .error(new ValidateError("邮箱不合法!")),
    //password 密码必填 6-32位
    password1: Joi.string().trim(true).min(6).max(32).required()
      .error(new ValidateError("密码必须是1-32位!")),
    //二次检验密码
    password2: Joi.string().valid(Joi.ref("password1"))
      .error(new ValidateError("两次密码必须相同!")),
    //昵称 最低2位
    nickname: Joi.string().trim(true).pattern(new RegExp("^[^\\s]+$")).min(2)
      .error(new ValidateError("昵称长度最低2位且不能包含空格!")),
  });

  return joiObject.validateAsync(data);
};



module.exports = {
  registerValidate
}

具体用法就自己查看joi的文档了,https://joi.dev/api/?v=17.4.0,目前最新是17版本

其中trim(true)是可以去除参数首尾空格。

external表示自定义异步校验,所以他被安排到了最后校验,所以如果在external中对参数进行操作,其他校验器是拿不到的,正因为他是异步的,所以我们在里面使用异步的请求,比如上面对数据进行查询,如果有相同的email就抛出错误。

external接受两个参数,一个要出触发的函数,另一个是说明文字。

如果是一个比较简单的校验,同步就能完成的,我们可以使用custom的方式,他的用法和external差不多,也是两个参数,函数和说明文字,只是他里面不用使用异步的方法。

开始校验

user.js:

const Router = require("koa-router");
const router = new Router({ prefix: "/v1/user" });
const { User } = require(`${process.cwd()}/models/user`);
const { registerValidate } = require(`${process.cwd()}/utils/validate/user`);



//注册用户
router.post("/register", async (ctx, next) => {
  //验证
  const { email, password1: password, nickname } = await registerValidate(ctx.request.body);
  // 验证通过
  console.log("验证通过")
});


module.exports = router;

当他能往下走的时候,说明验证已经通过了,我们就可以往数据库写入内容,写入内容我们也需要引入对象的模型。

const Router = require("koa-router");
const router = new Router({ prefix: "/v1/user" });
const { User } = require(`${process.cwd()}/models/user`);
const { registerValidate } = require(`${process.cwd()}/utils/validate/user`);
const { User } = require(`${process.cwd()}/models/user`);


//注册用户
router.post("/register", async (ctx, next) => {
  //验证
  const { email, password1: password, nickname } = await registerValidate(ctx.request.body);
  //验证通过加入数据库
  await User.create({ email, password, nickname });
});


module.exports = router;

写入数据后我们还需要返回给前端成功的信息。

成功信息返回

返回信息很多人可能是这样写:

ctx.body = {
  msg: xxxx,
  ....
}

如果每个接口都这样写是不是太累了,对象的格式都是一样的,返回的一些状态值也是一样的。

我们可以创建一个用于返回成功信息的错误对象,这样就能被全局错误捕获所捕获,然后返回给前端。

于是乎:

http-error.js:

//基础错误对象
class HttpError extends Error {
  constructor(msg = "服务器异常", errorCode = 10000, status = 400) {
    super();
    this.errorCode = errorCode;
    this.status = status;
    this.msg = msg;
  }
};

//校验不通过的错误对象
class ValidateError extends HttpError {
  constructor(msg, errorCode) {
    super();
    this.errorCode = errorCode || 10001;
    this.status = 200;
    this.msg = msg || "参数检验不通过!";
  }
};

//成功的错误对象
class Success extends HttpError {
  constructor(msg, errorCode) {
    super();
    this.errorCode = errorCode || 2000;
    this.status = 201;
    this.msg = msg || "参数检验不通过!";
  }
}



module.exports = {
  HttpError,
  ValidateError,
  Success
};

在路由里面使用:

const Router = require("koa-router");
const router = new Router({ prefix: "/v1/user" });
const { User } = require(`${process.cwd()}/models/user`);
const { registerValidate } = require(`${process.cwd()}/utils/validate/user`);
const { User } = require(`${process.cwd()}/models/user`);
const { Success } = require(`${process.cwd()}/core/http-error`);

//注册用户
router.post("/register", async (ctx, next) => {
  //验证
  const { email, password1: password, nickname } = await registerValidate(ctx.request.body);
  //验证通过加入数据库
  await User.create({ email, password, nickname });
  throw new Success("账号创建成功!");
});


module.exports = router;

版权申明

本文系作者 @木灵鱼儿 原创发布在木灵鱼儿 - 有梦就能远航站点。未经许可,禁止转载。

关于作者

站点职位 博主
获得点赞 0
文章被阅读 1158

相关文章