前两章,我们安装了 Mysql 运行环境,创建了 blog 数据库,创建了 user 表和相关字段定义,并成功地发起请求,接口解析且拿到了请求数据。
这篇文章,就开始完成登录注册逻辑的开发和数据的入库。
{
"name": "CoolApi",
"version": "1.0.0",
"description": "我的接口框架",
"type": "module",
"main": "server.js",
"scripts": {
"dev": "node server.js"
},
"dependencies": {
"mime-types": "^2.1.35",
"mysql2": "^3.10.3"
},
"devDependencies": {
"nodemon": "^3.1.4"
}
}在此之前呢,不知道大家有没有发现,每次都要重启接口服务,异常麻烦。
所以,我们可以安装一个 Npm 包 nodemon,可以监控代码的改动,自动重启接口服务。
同时呢,也将操作 Mysql 数据库的扩展 mysql2 给安装上。
{
"name": "CoolApi",
"version": "1.0.0",
"description": "我的接口框架",
"type": "module",
"main": "server.js",
"scripts": {
"dev": "node server.js",
"dev": "nodemon server.js"
},
"dependencies": {
"mime-types": "^2.1.35",
"mysql2": "^3.10.3"
},
"devDependencies": {
"nodemon": "^3.1.4"
}
}nodemon 的使用也很简单,把我们的脚本命令中的 node 替换成 nodemon 即可。
# 执行 pnpm run dev
[nodemon] files triggering change check: package.json
[nodemon] matched rule: **\*.*
[nodemon] changes after filters (before/after): 1/1
[nodemon] restarting due to changes...
[nodemon] package.json
[nodemon] starting `node server.js`
[nodemon] forking
[nodemon] child pid: 9436
服务已启动,监听端口为:3000执行 pnpm run dev 的效果如上。
一段小插曲,我们继续开发 用户登录注册功能。
用户注册流程
- 查询数据库,用户名是否存在。
- 如果存在,则提示,
用户已存在。 - 如果不存在,则进行下一步。
- 如果存在,则提示,
- 把用户名,密码,创建时间,插入到数据库中。
- 接口正常返回,并提示
注册成功。
用户登录流程
- 查询数据库,用户名是否存在。
- 如果不存在,则提示
用名不存在,请注册。 - 如果存在,这进行下一步。
- 如果不存在,则提示
- 将查询出的密码跟上传的密码进行对比。
- 如果不一致,则提示,
密码错误。 - 如果密码一致,则进行下一步。
- 如果不一致,则提示,
- 接口返回用户数据,并提示
登录成功。
顺便提一嘴,这个库是使用原生的 SQL 语法操作 Mysql,随着课程的深入,我们后面会换成更方便的操作库。
当我们查看 Mysql2 官网的时候,会发现有 3 种连接方式。

我们选择第二种,createPool 即可,createPoolCluster 是 createPool 的升级版,我们的项目用不着。
这是单连接和连接池的区别:
普通连接 (单连接)
适用场景:适用于请求量不高,或者每个请求都是独立的应用场景。特点:每次请求都会创建一个新的数据库连接,请求结束后关闭连接。优点:简单易用,适合小规模应用或脚本。缺点:频繁创建和销毁连接可能会影响性能,尤其是在高并发场景下。
连接池 (连接池模式)
适用场景:适用于请求量高,需要频繁访问数据库的应用,如 Web 应用服务器。特点:预先创建一定数量的数据库连接,并在请求到来时从池中获取连接,请求结束后将连接返回到池中,而不是关闭连接。优点:提高性能,减少连接创建和销毁的开销,能够更好地处理高并发请求。缺点:需要管理连接池的大小和生命周期,可能会占用更多的内存资源。
import mysql from "mysql2/promise";
const mysqlPool = mysql.createPool({
host: "localhost",
user: "root",
password: "root",
database: "blog",
port: 3306,
namedPlaceholders: true,
});
export { mysqlPool };我们单独创建一个 mysql.js 文件,代码如上。
提示: 记得先运行数据库软件。
import { mysqlPool } from "../mysql.js";
export default async (req) => {
try {
// 从连接池中获取一个数据库连接
const db = await mysqlPool.getConnection();
// 查询数据库是否有对应的用户数据
const result = await db.query({
sql: "SELECT version()",
});
console.log("🚀 ~ result:", result);
// 释放数据库连接
db.release();
// 返回成功信息
return {
code: 0,
msg: "注册成功",
};
} catch (err) {
console.log("🚀 ~ err:", err);
return {
code: 1,
msg: "未知错误",
};
}
};在用户注册接口中,引入 mysql.js 文件。
先来查询数据库版本,看看是否正常。
服务已启动,监听端口为:3000
🚀 ~ result: [ [ { 'VERSION()': '5.7.44' } ], [ `VERSION()` VARCHAR(6) NOT NULL ] ]可以看到,控制台打印了我们的数据库版本,是 5.7,说明数据库连上了。
我们看这个返回数据,是一个数组。
这是 Mysql2 的统一返回结构,数组的第一个值是操作得到的数据,数组的第二个值是相关的定义。
还记得我们之前说过的 做实验 吗?我们不要急着写功能,初学者,多打印,多看,确认数据库连接正常,查询正常,再进行后面的步骤。
数据库操作完毕,要记得 释放连接,这就好像吃饭的公筷一样,你不放回去,大家都拿到手里,其他人怎么夹菜呢。
import { mysqlPool } from "../mysql.js";
export default async (req) => {
try {
// 参数去掉前后空格
const username = req.body.username.trim();
const password = req.body.password.trim();
// ------------------------------------------------------
// 验证用户名参数
if (username.length < 2) {
return {
code: 1,
msg: "用户名太短",
};
}
// ------------------------------------------------------
// 验证密码参数
if (password.length < 6) {
return {
code: 1,
msg: "密码太短",
};
}
// ------------------------------------------------------
// 从连接池中获取一个数据库连接
const db = await mysqlPool.getConnection();
// 查询数据库是否有对应的用户数据
const [rows] = await db.query({
sql: "SELECT * FROM `user` WHERE `username`=:username LIMIT 1",
values: {
username: username,
},
});
console.log("🚀 ~ rows:", rows);
// ------------------------------------------------------
// 如果查到了用户数据,说明该用户名已注册
if (rows.length > 0) {
return {
code: 1,
msg: "用户已注册",
};
}
// ------------------------------------------------------
// 插入用户数据
const [result] = await db.query({
sql: "INSERT INTO `user` (`username`,`password`,`created_at`) VALUES (:username,:password,:created_at)",
values: {
username: username,
password: password,
created_at: Date.now(),
},
});
console.log("🚀 ~ result:", result);
// 释放数据库连接
db.release();
// 返回成功信息
return {
code: 0,
msg: "注册成功",
};
} catch (err) {
console.log("🚀 ~ err:", err);
return {
code: 1,
msg: "未知错误",
};
}
};接下来,实现注册的具体逻辑。按照分割线,一步步理解,不理解的在问答群艾特笔者即可。
其实一点也不难,一次理解一小部分,整个代码就理解了。

上图是用户注册功能的演示动图。

为了让我们对从数据库拿到的数据,有更深的印象,笔者写了两处打印日志。

最后,我们查看数据库,可以看到,用户信息已经插入了,注册功能初版完成!
// /apis/userLogin.js 文件
import { mysqlPool } from "../mysql.js";
export default async (req) => {
try {
// 参数去掉前后空格
const username = req.body.username.trim();
const password = req.body.password.trim();
// ------------------------------------------------------
// 验证用户名参数
if (username.length < 2) {
return {
code: 1,
msg: "用户名太短",
};
}
// ------------------------------------------------------
// 验证密码参数
if (password.length < 6) {
return {
code: 1,
msg: "密码太短",
};
}
// ------------------------------------------------------
// 从连接池中获取一个数据库连接
const db = await mysqlPool.getConnection();
// 查询数据库是否有对应的用户数据
const [rows] = await db.query({
sql: "SELECT * FROM `user` WHERE `username`=:username LIMIT 1",
values: {
username: username,
},
});
console.log("🚀 ~ rows:", rows);
// ------------------------------------------------------
// 如果查到了用户数据,说明该用户名已注册
if (rows.length <= 0) {
return {
code: 1,
msg: "用户未注册",
};
}
// ------------------------------------------------------
// 判断密码是否匹配
const [user] = rows; // rows是一个数组,我们这里用user变量去取数组的第一个值
if (user.password !== password) {
return {
code: 1,
msg: "密码错误",
};
}
// 释放数据库连接
db.release();
// 返回成功信息
return {
code: 0,
msg: "登录成功",
data: user,
};
} catch (err) {
console.log("🚀 ~ err:", err);
return {
code: 1,
msg: "未知错误",
};
}
};登录功能,就不多赘述了,跟注册所差无几。

点击登录按钮,就能拿到登录的用户数据了。
至此,我们的登录和注册功能,就完成了。
这是我们的第一个初步版本,后续还会进一步完善。
不知道看这里,是不是发现,其实后端开发,也很简单呢?
