木灵鱼儿
阅读:2911
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;
版权申明
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿 - 有梦就能远航站点。未经许可,禁止转载。
相关推荐
centos 安装最新版 node.js
[hide]先用yum 安装一次node先升级yum update 提示下载程序,回复y安装nodeyum install nodejsyum安装的node一般都不是最新的,所以我们还需要升级node的版本npm i n -g全局安装一个n插件n lts表示安装最新的稳定版!一些常用命令n ls查看已安装的node版本n rm 16.0.3删除16.0.3版本更多功能阅读插件文档:n等待安装完毕后,此时其实版本已经安装好了,但是输入node -v还是低版本,是因为centos的用户缓存问题。我们退出登录再登录就会刷新缓存了,此时的node -v输出的就是最新版本exit 退...
node npm yarn 如何同时运行多个指令
node的bash命令其实是有对应的指令字符的,但是,这个指令只能再linux,mac上才有生效,再windows是无效的,所以了解一下就行。命令说明&&顺序执行多条命令,当碰到执行出错的命令后将不执行后面的命令&并行执行多条命令||顺序执行多条命令,当碰到执行正确的命令后将不执行后面的命令|管道符windows上进行多命令"scripts": { "dev": "cross-env NODE_ENV=development webpack --env development --progress -...
纯css来做表单校验样式
css3新增了三个伪类::required、:valid、:invalid:required 表示input不能为空时使用的:valid 表示通过,表单元素和form表单都有的伪类:invalid 表示不通过,表单元素和form表单都有的伪类其实如果要做一个表单css校验样式,:valid和:invalid就行了,但是实际操作上,:invalid还是有一些问题的。当表单元素有required属性的时候,该表单元素默认就是:invalid,也就说,必填的表单元素,一开始就是不通过。所以,如果此时设置:invalid伪类样式,是不合适的。解决办法就是:使用:placeholder-shown...

koa教程2 HttpBearerAuth 传递token
前端发送token到后端,一般有三种方式:链接中携带token,query参数post这种请求body中携带token头信息携带token但是事实上http已经为我们提供了传token的方式,是一个相对来说比较安全的方式,就是HttpBearerAuth 其实他也是一个头信息来着,只是相对来说多了一点操作,在apipost软件中,我们可以直接可视化设置如果是axios,则是需要添加一个头信息:axios({ method: 'get', url: url, responseType: 'blob', headers: { 'Authoriz...

koa教程2 微信openid登录
微信的openid,前端登录时,会发送一个code码到后端,后端接收到这个code,然后配合appid、appsecret参数,像wx发送一个get请求。wx的请求地址:GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code具体查看文档:微信官方文档-服务端可以看到这段get请求有四个参数:属性类型默认值必填说明appidstring 是小程序 appIdsecretstring 是...
koa教程2 权限分级控制
在之前的代码中,我们使用了一个scope属性来表示用户的权限,但是scope是一个数字,他的阅读性是非常差的,当其他人开发的时候,可能并不知道你这个数字是什么意思?所以,我们需要将它转义成文本。为了方便判断,我们在enum.js中增加一个用户等级的对象enum.js://通用判断是否存在该类型 function isThisType(val) { let flag = false; Object.keys(this).find(key => { if (this[key] === val) { return flag = true; } })...
koa教程2 token鉴权
之前我们在token中传入我们的自定义参数,现在我们要做一个token鉴权,很简单,如果他的token合法,就可以访问这个路由,如果不合法,就打回。这个也不能说是真正意义上的鉴权,因为他还没有判断scope值,所以只能说是简单判断。做这个判断我们就可以通过中间件的形式,于是我们在middlewares目录下创建一个auth.js文件auth.js:const parseBearerToken = require("@utils/paresBearerToken"); const jwt = require("jsonwebtoken"); cons...
koa教程2 用户登录
登录类型用户注册之后,自然是用户登录,登录的时候我们需要考虑到登录的方式,往往在正式的项目里面,登录的方式可能会有很多种:账号密码登录手机号登录小程序一键登录那么我们登录的时候就要进行判断,设置一个type的属性,用于在登录时判断用户是什么类型的登录,这个由前端那边设定参数。type:1为账号密码登录,2为手机号登录,3为小程序一键登录作为判断,我们可以写一个查询表(枚举),在项目根目录创建一个lib目录,在里面创建一个enum.js文件。enum.js://通用判断是否存在该类型 function isThisType(val) { let flag = false; Obje...
node 自定义路径别名
用过vue cli的话,对路径中的@应该不陌生,他表示根目录,但是在node的环境里面,我们编写模块并引入时,并没有这种方便的写法。在node环境中,我们可以通过process.cwd()来表示根目录,但是这样的话,每次使用绝对路径引入,路径总是需要写一大堆拼接。const db = require(`${process.cwd()}/config/config`).database;这样略显麻烦,于是我们可以在全局写一个引入插件的方法:global.myRequire = function (path) { return require(`${process.cwd()}/${pa...
koa教程2 密码加密
默认情况下,我们通过User.create({ email, password, nickname });模型传入的数据,是无加密的,也就是说,在数据库中密码是明文显示的,这样肯定是不行,我们需要使用bcrypt插件进行加密yarn add bcryptjs --dev打开models/user.jsuser.js:const bcrypt = require("bcryptjs"); const { sequelize } = require(`${process.cwd()}/core/db`); const { Sequelize, Model, DataTy...
