Koa学习3:用户添加、错误处理
模型
在src
目录下创建model
目录,用来存放模型
创建用户模型
user.model.js
注意: UUID
类型是无法自增的,将id设置为UUID
类型时只需要为其指定默认值即可
// 数据类型
const { DataTypes } = require('sequelize');
// 导入已经连接了数据库的Sequlize对象
const sequelize = require('../db/seq');// 创建模型
const User = sequelize.define('zd_user', // 对应数据库里的表,默认会变成复数形式也就是 zd_users// 定义模型的属性(表的字段){// id会被自动创建,也可以不定义id: {type: DataTypes.UUID, // UUID 类型unique: true, // 是否唯一primaryKey: true, // 是否是主键comment: '主键', // 注释defaultValue:DataTypes.UUIDV4 // 设置uuid的生成规则},// 用户名user_name: {type: DataTypes.STRING, // 对应VARCHAR(255)unique: true,allowNull: false,comment: '用户名',// 验证器,用于校验格式,具体见官方文档validate: {isAlphanumeric: true, // 仅允许字符和数字len: [6, 10], //长度},},// 密码password: {type: DataTypes.CHAR(64),allowNull: false,comment: '密码',validate: {isAlphanumeric: true, // 仅允许字符和数字len: [6, 10], //长度},},// 是否是vipis_vip: {type: DataTypes.BOOLEAN,allowNull: false,defaultValue: 0, // 默认值,BOOLEAN类型的值只有0和1,填写true和false也会被自动转换comment: '是否是vip',},}
);// 模型同步,将创建表,如果表已经存在,则将其首先删除
// User.sync({ force: true });module.exports = User;
在项目根目录下运行该js
文件,创建表(要在项目根目录下,不然无法读取到.env中的变量)
默认情况下,Sequelize 使用数据类型 DataTypes.DATE 自动向每个模型添加 createdAt 和 updatedAt 字段. 这些字段会自动进行管理 - 每当你使用Sequelize 创建或更新内容时,这些字段都会被自动设置. createdAt 字段将包含代表创建时刻的时间戳,而 updatedAt 字段将包含最新更新的时间戳.
注意: 这是在 Sequelize 级别完成的(即未使用 SQL触发器 完成). 这意味着直接 SQL 查询(例如,通过任何其他方式在不使用 Sequelize 的情况下执行的查询)将不会导致这些字段自动更新.
如果不想要下面这两个字段可以设置timestamps
为false
sequelize.define('User', {// ... (属性)
}, {timestamps: false
});
添加用户
user.service
// 导入用户模型
const User = require('../model/user.model');
class UserService {// 创建用户async createUser(user_name, password) {// 插入数据,新增成功后会返回该条数据的对象const res = await User.create({ user_name, password });return res;}// 获取用户基本信息async getUserInfo(params = { id, user_name, is_vip }) {// 处理where条件const whereOpt = {};for (let key in params) {if (![undefined, null, ''].includes(params[key])) {whereOpt[key] = params[key];}}// 查询符合条件的第一条数据const res = await User.findOne({// 指定要返回的属性attributes: ['id', 'user_name', 'is_vip', 'createdAt', 'updatedAt'],// where条件where: whereOpt,});return res ? res : null;}
}// 导出
module.exports = new UserService();
user.controller
/*** 处理与用户有关的请求*///导入service
const { createUser, getUserInfo } = require('../service/user.service');class UserController {//注册async register(ctx, next) {// 1、获取数据const requistBody = ctx.request.body;// 合法性判断if (!requistBody.user_name || !requistBody.password) {console.error('用户名或密码为空');ctx.body = {code: '10001', // 错误code,用于定义错误类型,团队内部自行约定message: '用户名或密码为空',data: null,};return;}// 合理性,判断该用户是否已经存在,用户名是唯一的if (await getUserInfo({ user_name:requistBody.user_name })) {ctx.body = {code: '10002',message: '该用户已存在,请勿重新注册',data: null,};return;}// 2、操作数据库const res = await createUser(requistBody.user_name, requistBody.password);// 3、返回响应结果ctx.body = {code: 0,message: '用户创建成功',data: null,};}// 登录async login(ctx, next) {ctx.body = '登录';}
}// 导出实例化对象
module.exports = new UserController();
需要注意,当输入文本之类的信息时要避免字符串中的特殊字符,需要将其转义为HTML实体,避免恶意脚本注入。
const str = "<script>alert('hello world');</script>";
const escapedStr = sequelize.escape(str);
console.log(escapedStr); // 输出:"<script>alert('hello world');</script>"
错误处理
从上面的代码可以看到对于错误处理并不完善可能会出现一些其他的错误,并且如果每一个接口都要这样写的话是很难维护的,因此需要一个中间件进行统一的错误处理。
在src
下创建一个constant
用来定义一些常量,创建一个middleware
文件夹用来存放错误处理的逻辑
错误类型
constant/user.err.type.js
用于记录与用户有关的错误类型
module.exports={userFormatError:{code: '10001', // 错误code,用于定义错误类型,团队内部自行约定message: '用户名或密码为空',data: null,},userAlreadyExisted:{code: '10002',message: '该用户已存在,请勿重新注册',data: null,},userRegisterErr:{code: '10003',message: '用户注册失败',data: null,}
}
constant/err.type.js
错误类型的统一出口,后续会加一些其他的错误类型
// 用户错误
const UserErr = require('./user.err.type');module.exports = {UserErr,
};
中间件
middleware/user.middleware.js
// 导入service层
const { getUserInfo } = require('../service/user.service');
// 导入错误类型
const { UserErr } = require('../constant/err.type');// 用户注册校验
const userRegisterValidator = async (ctx, next) => {// 获取入参const requistBody = ctx.request.body;// 合法性判断if (!requistBody.user_name || !requistBody.password) {// console.error 打印的内容会被记录到服务器的日志里console.error('用户名或密码为空:', requistBody);//使用了Koa的错误处理机制ctx.app.emit('error', UserErr.userFormatError, ctx);return;}// 合理性,判断该用户是否已经存在,用户名是唯一的if (await getUserInfo({ user_name: requistBody.user_name })) {console.error('该用户已存在,请勿重新注册:', requistBody);ctx.app.emit('error', UserErr.userAlreadyExisted, ctx);return;}// 验证通过后交由一个中间件处理await next();
};module.exports = {userRegisterValidator,
};
注意:
- console.error 打印的内容会被记录到服务器的日志里;
ctx.app.emit('error', UserErr.userAlreadyExisted, ctx)
,使用koa提供的错误机制让 Koa 自动捕获错误并返回给客户端
使用
router/user.route.js
// 注册
router.post('/register', userRegisterValidator, register);
先执行userRegisterValidator
中间件进行注册校验,校验通过后在执行register
中间件进行注册
app/index.js
const app = new Koa();
// koa-body中间件要在所有的路由之前
app.use(koaBody());// 中间件
app.use(userRouter.routes());// 进行统一的错误处理
app.on('error', (errType, ctx) => {ctx.body = errType;
});module.exports = app;
相关文章:

Koa学习3:用户添加、错误处理
模型 在src目录下创建model目录,用来存放模型 创建用户模型 user.model.js 注意: UUID类型是无法自增的,将id设置为UUID类型时只需要为其指定默认值即可 // 数据类型 const { DataTypes } require(sequelize); // 导入已经连接了数据库…...

网络安全入门学习第十五课——PHP基础
文章目录 一、WEB技术1、什么是web2、B/S架构3、C/S架构 二、PHP概述1、PHP是什么2、PHP受欢迎的原因3、基于MVC模式的PHP框架4、常用编译工具5、PHP环境搭建6、开发工具 三、PHP基本语法格式1、标记2、输出语句3、注释4、标识符 四、数据与运算1、常量1.1、常量定义1.2、预定义…...

电子科技大学 数学专业-功不唐捐,玉汝于成
电子科技大学 数学专业 功不唐捐,玉汝于成 1.本科背景 本科是坐落于湖南湘潭的湖南科技大学,专业为网络工程专业,因热爱数学专业,所以决定跨考数学专业。 本科专业课平均成绩85,排名10/104。CET 4 474分,…...
Android10.0 iptables用IOemNetd实现删除子链功能的实现
1.前言 在10.0的系统rom定制化开发中,在system中netd网络这块的产品需要中,会要求设置屏蔽ip地址之内的功能, liunx中iptables命令也是比较重要的,接下来就来在IOemNetd这块实现删除创建子链的相关功能 2. iptables用IOemNetd实现删除创建子链功能的实现的核心类 syste…...

OpenGL光照之光照贴图
文章目录 漫反射贴图镜面光贴图放射光贴图代码 每个物体都拥有自己独特的材质从而对光照做出不同的反应的方法。这样子能够很容易在一个光照的场景中给每个物体一个独特的外观,但是这仍不能对一个物体的视觉输出提供足够多的灵活性。 我们将整个物体的材质定义为一个…...

2018~2019 学年第二学期《信息安全》考试试题(B 卷)
北京信息科技大学 2018 ~2019 学年第 2 学期 《信息安全》课程期末考试试卷 B 课程所在学院:计算机学院 适用专业班级:计科 1601-06,重修 考试形式:(闭卷) 一. 选择题(本题满分 10 分,共含 10 道小题,每小题 1 分) 网络中存在的安全漏洞主…...
LeetCode-C#-0002.两数相加
0.声明 该题目来源于LeetCode 如有侵权,立马删除。 解法不唯一,如有新解法可一同讨论。 1.题目 0002两数相加 给你两个非空的链表,表示两个非负的整数,它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一…...

访问修饰符private,default,protected,public访问等级区别
private:private是最严格的访问修饰符,它将成员声明为私有的。私有成员只能在声明它们的类内部访问,其他类无法直接访问私有成员。这样可以确保数据的封装性和安全性。 default(默认):如果没有明确指定访问…...

阿里云(Linux)安装Docker教程
首先安装docker,需要找到帮助文档,那肯定是我们的官网: Install Docker Engine on CentOS | Docker Documentation 找到对应的位置,这里是安装在CentOS中,版本需要Ce…...
Linux C编程基础:获取时间
1.前言 对于linux下的编程,无论是用户态还是内核态,时间获取都是经常需要使用到的。以下分别从用户态和内核态整理了几个常用的时间获取接口,供编写代码时快速查阅。 2.用户态获取时间 2.1 clock_gettime() #include <time.h>int c…...
Spring核心注解
1、Bean注解 作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中位置: 一般出现在方法上面属性: name:用于指定bean的id。当不写时,默认值是当前方法的名称细节:当我们使用注解配置方法时,如果方法有参数,…...

哈希表原理,以及unordered_set/和unordered_map的封装和迭代器的实现
哈希表 unordered系列unordered_set和unordered_map的使用哈希哈希概念哈希冲突哈希函数闭散列开散列哈希表的扩容哈希表源码(开散列和闭散列) 封装unordered_set/和unordered_map,以及实现迭代器节点定义unordered_set定义unordered_map定义…...

如何把歌曲里的伴奏音乐提取出来,分享几个方法给大家!
对于一首歌,我们都知道,它有两部分组成:背景音乐人声。这两者合在一起,便是我们经常听的歌。部分用户想要直接获取歌曲伴奏,那么可以在UU伴奏网上下载。 操作方法比较简单,直接搜索想要的歌曲名称就可以了…...

区块链产业快速发展 和数集团开启区块链应用新时代
UTONMOS区块链游戏要来了。 就在5月底,UTONMOS品牌所属公司上海和数集团在泰国发布了【神念无界】系列的多款国际版链游,包括【神念无界-源起山海】、【北荒传奇】、【神宠岛】、【神农园】等区块链游戏。 以【神念无界-源起山海】为例,其是…...
初出茅庐的小李博客之常见字符串函数使用
C语言字符数组与字符串数组 在C语言中,字符数组和字符串数组实际上是同一种类型。字符串是由字符组成的字符数组,通常以空字符 ‘\0’ 结尾。C语言中的字符串是一种常见的数据类型。我们可以通过两种方式定义字符数组跟字符串数组 char charArray[10];…...
运筹学工程化流程和常见的运筹学算法分类以及常见软件
文章目录 前言运筹学工程化流程运筹学算法分类运筹学软件参考文献 前言 自2023年初新冠疫情管控放开后,各家公司各类岗位的人员都有被裁的消息传出,但用人市场上运筹学算法岗位却反其道行之,用工出现了激增。可以预见的是数据算法将从传统的…...

JAVA面向对象(三)
第三章 封装与继承 目录 第三章 封装与继承 1.1.封装 1.2.包 1.3.访问权限控制 1.4.static修饰符 1.4.1.成员变量 1.4.2.成员方法 1.4.3.代码块 总结 内容仅供学习交流,如有问题请留言或私信!!!!࿰…...
前端面试题---跨域处理和异常、错误处理
一.跨域处理 在前端开发中,当我们在浏览器中向不同域名或端口发起请求时,就会遇到跨域请求的限制。为了处理跨域请求,有几种常见的方法 1.JSONP(JSON with Padding) JSONP是一种利用 <script> 标签可以跨域加载…...

网络安全之反序列化漏洞分析
简介 FastJson 是 alibaba 的一款开源 JSON 解析库,可用于将 Java 对象转换为其 JSON 表示形式,也可以用于将 JSON 字符串转换为等效的 Java 对象分别通过toJSONString和parseObject/parse来实现序列化和反序列化。 使用 对于序列化的方法toJSONStrin…...
19 贝叶斯线性回归
文章目录 19 贝叶斯线性回归19.1 频率派线性回归19.2 Bayesian Method19.2.1 Inference问题19.2.2 Prediction问题 19 贝叶斯线性回归 19.1 频率派线性回归 数据与模型: 样本: { ( x i , y i ) } i 1 N , x i ∈ R p , y i ∈ R p {\lbrace (x_i, y_…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...

蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...