我转过几个弯 绕过那个小雨楼
拿着蒲扇摆着衣衫渡着紧箍咒
不问天涯不停留 喝过几壶酒
不过年少白头道义放胸口
倘若明天之后 遥看前尘剑封侯
似那天上神仙无所求
朝朝暮暮君如梦醒十分不为何理由
是真是假是惶恐是无休
路过这风雨花满楼 片刻都不停留
我本这书生进京赶考留下许多愁
你问有没有时候 我叹这天道默悠悠
能否与我一醉方休
又过了几个弯 算尽天量道莫慌
踏这田园闻这芳草香
跌跌撞撞仗剑天涯折煞不枉无笔良
是梦是幻是温柔是家乡
路过这风雨花满楼 片刻都不停留
我本这书生进京赶考留下许多愁
你问有没有时候 我叹这天道默悠悠
能否与我一醉方休
路过这风雨花满楼 片刻都不停留
我本这书生进京赶考留下许多愁
你问有没有时候 我叹这天道默悠悠
能否与我一醉方休
谁能与我一醉方休
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)