Koa学习3:用户添加、错误处理

news2024/11/19 9:33:45

模型

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], //长度
      },
    },
    // 是否是vip
    is_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();

g)
在这里插入图片描述

需要注意,当输入文本之类的信息时要避免字符串中的特殊字符,需要将其转义为HTML实体,避免恶意脚本注入。

const str = "<script>alert('hello world');</script>";
const escapedStr = sequelize.escape(str);
console.log(escapedStr); // 输出:"&lt;script&gt;alert(&#x27;hello world&#x27;);&lt;/script&gt;"

错误处理

从上面的代码可以看到对于错误处理并不完善可能会出现一些其他的错误,并且如果每一个接口都要这样写的话是很难维护的,因此需要一个中间件进行统一的错误处理。

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;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/633603.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

集合导题、刷题、考试全套完整流程,专业强大的功能,提高刷题学习效率和企业的培训效率

土著刷题微信小程序v1.15&#xff0c;主要是迭代了考试模块的进阶功能&#xff0c;对考试模块进行了一次升级改造。 由于在v1.15开发期间&#xff0c;收到了违规内容整改的通告&#xff0c;为了遵守相关法律法规&#xff0c;让小程序能够平稳安全地运营下去&#xff0c;我们特此…

我说用count(*)统计行数,面试官让我回去等消息...

前言 1 count&#xff08;*&#xff09;为什么性能差&#xff1f; 2 如何优化count&#xff08;*&#xff09;性能&#xff1f; 2.1 增加redis缓存 2.2 加二级缓存 2.3 多线程执行 2.4 减少join的表 2.5 改成ClickHouse 3 count的各种用法性能对比 前言 最近我在公司优…

Consul单机集群

一、准备工作 1、下载consul consul各版本下载地址&#xff0c;点击如下连接前往&#xff1a; Consul Versions | HashiCorp Releases 本案例使用版本&#xff1a;Consul v1.15.0 &#xff1b;下载的文件解压皆可&#xff0c;consul为可执行文件。 2、创建目录&#xff1a…

移动安全app渗透测试之渗透流程、方案及测试要点讲解

被产品经理分到了个app测试的活&#xff0c;&#xff08;话说为啥是产品经理给派活&#xff0c;我不是归技术总监管么&#xff09;&#xff0c;包含安卓端的和ios端的&#xff0c;有点懵逼&#xff0c;说好的web渗透测试和服务器端渗透测试呢&#xff0c;虽然懵逼&#xff0c;不…

【V4L2】v4l2框架分析之video_device

文章目录 &#x1f53a;一、video_device分析&#xff08;1-1&#xff09;struct video_device结构&#xff08;1-2&#xff09;struct v4l2_ioctl_ops结构&#xff08;1-3&#xff09;v4l2_file_operations结构 &#x1f53a;二、注册video设备&#x1f53a;三、卸载清除video…

华为OD机试真题B卷 JavaScript 实现【自守数】,附详细解题思路

一、题目描述 自守数是指一个数的平方的尾数等于该数自身的自然数。例如&#xff1a;25^2 625&#xff0c;76^2 5776&#xff0c;9376^2 87909376。请求出n(包括n)以内的自守数的个数。 数据范围&#xff1a; 1≤n≤10000 二、输入描述 int型整数。 三、输出描述 n以内…

Maven了解及使用

套用一下常用的what, why, how 对maven进行了解。 首先&#xff0c;what&#xff1f; maven是什么&#xff1f; 1、Maven是一个项目管理工具&#xff0c;它包含了一个项目对象模型 (Project Object Model)&#xff0c;一组标准集合&#xff0c;一个项目生命周期(Project Lifecy…

《C# 教程》菜鸟教程学习笔记

学习地址 ######C#有用的网站 C# Programming Guide - 介绍了有关关键的 C# 语言特征以及如何通过 .NET 框架访问 C# 的详细信息。Visual Studio - 下载作为 C# 集成开发环境的 Visual Studio 的最新版本。Go Mono - Mono 是一个允许开发人员简单地创建跨平台应用程序的软件平台…

I.MX6ull GPT高精度定时器

一 简介 GPT的全称是General Purpose Timer&#xff0c;它是一个32位的向上的定时器&#xff0c; GPT 定时器也可以跟一个值进行比较&#xff0c;当计数器值和这个值相等的话就发生比较事件&#xff0c;产生比较中断。GPT 定时器有一个 12 位的分频器&#xff0c;可以对 GPT 定…

sqli-labs靶场通关(1-10)

这次的靶场主要为sql注入的练习&#xff0c;在练习靶场前我们需要了解以下mysql数据库。 数据库是一个用于存储和管理数据的仓库。数据按照特定的格式存储&#xff0c;可以对数据库中的数据进行增加、修改、删除和查询操作。数据库的本质是一个文件系统&#xff0c;按照一定的…

2023年腾讯云618年中大促活动整理汇总

2023年腾讯云618年中大促活动正在进行中&#xff0c;目前正是腾讯云最优惠的时候&#xff0c;小编给大家整理汇总了腾讯云618活动时间、活动入口、活动内容&#xff0c;大家记得抓住上云好时机&#xff01; 一、2023年腾讯云618活动时间 2023年05月25日-2023年6月30日 二、20…

【024】C++对C的扩展之命名空间namespace详解

C对C的扩展 引言一、面向对象编程概述1.1、面向过程1.2、面向对象 二、作用域运算符 :: &#xff08;双冒号&#xff09;三、命名空间 namespace3.1、命名空间使用语法3.2、using声明命名空间中的成员可用3.3、using声明整个命名空间可用 总结 引言 &#x1f4a1; 作者简介&…

【浅谈DBA职业生涯之误操作篇---读书笔记】

&#x1f448;【上一篇】 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 【下一篇】&#x1f449; &#x1f53b;【&#x1f4a3; 话题引入&#xff1a;请列举你在从事 DBA 生涯中,最难以忘怀的一次误操作】 &#x1f6a9; 该话题覆盖…

【算法】深入了解数据压缩算法(无损压缩和有损压缩)

目录 1 引言&#xff1a; 1 数据压缩的重要性和应用场景 2 压缩算法的基本原理和分类 2. 无损压缩算法 2.1 哈夫曼编码 2.1.1 哈夫曼编码的原理和步骤 2.1.2 实现一个简单的哈夫曼编码器 2.2 字典编码 2.2.1 LZW算法的原理和步骤 2.2.2 实现一个基于LZW算法的压缩程序…

力扣笔记(每日随机一题)—— 二叉树的中序遍历

问题&#xff08;简单&#xff09; 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/binary-tree-inorder-traversal/ 示例 1 输入&#xff1a;root […

诡异BUG:DIV 的 margin 设置影响父级

参考资料&#xff1a;1、【web前端】23.解决内部div的margin影响外部div的margin_Anabel Chen的博客-CSDN博客 2、元素之间设置margin的影响及原因 有如下代码&#xff1a; <!doctype html> <html> <head><meta http-equiv"Content-Type" co…

RPC——RPC协议介绍及原理详解

common wx&#xff1a;CodingTechWork 介绍 RPC框架 概念 RPC&#xff08;Remote Procedure Call Protocol&#xff09; 远程过程调用协议。RPC是一种通过网络从远程计算机程序上请求服务&#xff0c;不需要了解底层网络技术的协议。RPC主要作用就是不同的服务间方法调用就…

Java蓝桥杯

目录 往年真题 题目分类 搜索 动态规划 并查集 贪心算法 二分查找 输入输出 图论 其他 往年真题 2022年第十三届蓝桥杯大赛软件类决赛Java研究生组真题 - 题库 - C语言网 2021年蓝桥杯第十二届省赛及国赛真题 - 题库 - C语言网 2020年蓝桥杯第十一届省赛及国赛真题…

[创业之路-73] :如何判断一个公司或团队是熵增:一盘散沙、乌合之众,还是,熵减:凝聚力强、上下一心?

前言&#xff1a; 一盘散沙、乌合之众&#xff1a; 凝聚力强、上下一心&#xff1a; 一、股权结构与利益分配 一盘散沙、乌合之众 凝聚力强、上下一心 股权结构过于松散和平均&#xff0c;无决策者&#xff0c;常常陷入无休止的争论股权结构层次结构&#xff0c;有最终决策者…

0302nacos配置运行-docker-macos apple arm64

1 已有镜像 拉取镜像 docker pull zhusaidong/nacos-server-m1:2.0.3运行容器-单机模式运行配置mysql数据库 第一步&#xff1a;创建挂载目录和文件 创建nacos 日志目录、配置目录 直接运行镜像&#xff0c;命令行或者图形界面进入容器&#xff0c;找到配置文件home/nacos/con…