【nodejs+mysql2+docker】node后端开发+docker部署简记
前言
最近朋友在写个人博客,我友情客串帮忙做一个简易的后端,于是有了这篇笔记,我选择的技术栈是node(express) + mysql
,部署使用docker
,简单记录一下,先说明本人没有专业的node
后端开发经验,纯属自己硬凑,有不专业的地方敬请谅解
项目结构思考
由于没有专业的node
后端开发经验,我个人感觉应该将数据库操作和业务操作单独分开,另外统一接口返回格式,具体操作再细分,所以有了以下项目结构
敲代码
文件太多,只挑几个代表示例,大部分操作都是不困难的,所有注释均是Ai
生成
接口返回模版
/**
* 类 IRM 用于管理响应结果,提供成功和错误响应的标准化格式。
*/
class IRM {
/**
* 构造函数,初始化响应对象。
*/
constructor() {
// 初始化响应对象,默认状态码为 -1,消息为空,数据为空对象
this.response = {
code: -1,
msg: '',
data: {}
};
}
/**
* 重置响应对象为初始状态。
*/
$initRes() {
this.response = {
code: -1,
msg: '',
data: {}
};
}
/**
* 设置成功的响应。
*
* @param {Object} data - 成功时返回的数据。
* @returns {Object} 包含成功状态码、消息和数据的响应对象。
*/
success(data) {
this.$initRes();
this.response.code = 200;
this.response.msg = "success";
this.response.data = data;
return this.response;
}
/**
* 设置错误的响应。
*
* @param {number} code - 错误状态码。
* @param {string} msg - 错误消息。
* @returns {Object} 包含错误状态码、消息和空数据的响应对象。
*/
error(code, msg) {
this.$initRes();
this.response.code = code;
this.response.msg = msg;
this.response.data = {};
return this.response;
}
}
// 导出两个 IRM 实例,IRT 和 DBIRT,区分数据库模版和业务模版
export const IRT = new IRM();
export const DBIRT = new IRM();
获取数据库连接
/**
* 获取数据库实例
* 如果已经连接,则直接返回实例
* 否则等待连接
*/
export const getDBInstannce = async () => {
if (connectionInstance) {
return connectionInstance;
}
return new Promise(async (resolve) => {
console.error('数据库未连接,无法获取db实例');
await connectUserDatabase()
let checkInterval = setInterval(() => {
console.log('等待数据库连接...');
if (connectionInstance) {
clearInterval(checkInterval);
console.log('db连接健康');
resolve(connectionInstance);
}
}, 1000);
})
}
处理登录请求(业务层操作)
/**
* 处理用户登录的路由
* @param {Object} req - 请求对象,包含email和password
* @param {Object} res - 响应对象
*/
router.post('/login', async (req, res) => {
try {
// 从请求体中解构出用户登录信息
const { email, password } = req.body;
// 调用用户登录函数
let { data, code, msg } = await userLogin(email, password);
if (code === 200) {
if (data.data.length === 0) {
res.json(IRT.error(40101, "用户不存在"))
return
}
// 使用MD5加密密码进行比较
let pwd = generateMD5(password);
if (data.data[0].password !== pwd) {
res.json(IRT.error(40102, "密码错误"))
return
}
// 准备用户信息和登录token
let user_id = data.data[0].id
let remember_token = data.data[0].remember_token
// 查询用户登录状态
let login_Status = await queryUserLoginStatus(remember_token)
// 根据登录状态返回相应的结果
if (login_Status?.data?.results[0]?.login_token) {
res.json(IRT.success({
login_token: login_Status?.data?.results[0].login_token,
userInfo: {
...data.data[0],
password: null,
remember_token: null
}
}))
return
}
// 生成新的登录token
let login_token = generateMD5(email + Date.now());
// 记录用户登录token
let login_data = await userLoginToken(user_id, remember_token, login_token);
if (login_data.code == 200) {
res.json(IRT.success({
login_token: login_token,
userInfo: {
...data.data[0],
password: null,
remember_token: null
}
}))
return
}
if (login_data.code == 40103) {
res.json(IRT.error(40103, login_data.msg))
return
}
return
}
res.json(IRT.error(500, msg))
} catch (error) {
console.log(error);
res.json(IRT.error(500))
}
})
处理用户登录(数据层)
// 用户登录函数
/**
* 用户登录
* @param {string} email - 用户邮箱
* @param {string} password - 用户密码
* @returns {Object} - 登录结果
*/
export async function userLogin(email, password) {
// 1. 验证输入数据是否完整
if (!email || !password) {
return DBIRT.error(400, "请输入完整的登录信息");
}
const query = 'SELECT * FROM users WHERE email = ?';
try {
let [results] = await db.execute(query, [email]);
return DBIRT.success({
data: results
});
} catch (error) {
return DBIRT.error(400, error);
}
}
…
敲完代码之后就是部署了,因为docker
部署最简单方便,所以就这种方式了,总体就是下面几步
- 编写
Dockerfile
# 使用官方 Node.js 镜像作为基础镜像
FROM node:20
# 创建并设置工作目录
WORKDIR /usr/src/app
# 复制 package.json 和 package-lock.json(如果有的话)
COPY package*.json ./
# 安装依赖
RUN npm install
# 复制其他项目文件
COPY . .
# 暴露应用运行的端口
EXPOSE 3000
# 启动应用
CMD ["node", "index.js"]
- 构建
docker
镜像
docker build -t node-server .
- 登录到阿里云镜像服务
- 使用
docker login xxxx
登录到阿里云 - 使用
docker tag
为本地镜像设置别名 - 使用
docker push
推送到阿里云镜像服务器上 - 登录到自己的服务器上,使用
docker login xxxx
登录阿里云 - 使用
docker pull
拉取镜像到本地 - 使用
docker run -d -p 80:3000 --name node-server xxxxx
运行容器,并将3000端口映射到本机的80端口上
端口根据具体的需求改
测试
最后请求服务器的接口,测试一下是否正常运行,很幸运,正常返回数据
{
"code": 200,
"msg": "success",
"data": {
"login_token": "a0151db81e9f622719e1b66ca57e7d42",
"userInfo": {
"id": 12,
"username": "test",
"email": "test@test.com",
"password": null,
"nickname": "test",
"profile_picture": null,
"bio": null,
"role": "user",
"status": "active",
"phone_number": "18800008998",
"address": null,
"created_at": "2025-02-19T09:26:54.000Z",
"updated_at": "2025-02-19T09:26:54.000Z",
"last_login": null,
"remember_token": null
}
}
}
总结
此文主要是简记,总结一下经验,长路漫漫,诸君共勉