【nodejs+mysql2+docker】node后端开发+docker部署简记

前言

最近朋友在写个人博客,我友情客串帮忙做一个简易的后端,于是有了这篇笔记,我选择的技术栈是node(express) + mysql,部署使用docker,简单记录一下,先说明本人没有专业的node后端开发经验,纯属自己硬凑,有不专业的地方敬请谅解

项目结构思考

由于没有专业的node后端开发经验,我个人感觉应该将数据库操作和业务操作单独分开,另外统一接口返回格式,具体操作再细分,所以有了以下项目结构


敲代码

文件太多,只挑几个代表示例 ,大部分操作都是不困难的,所有注释均是Ai生成

接口返回模版

javascript 复制代码
/**
 * 类 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();

获取数据库连接

javascript 复制代码
/**
 * 获取数据库实例
 * 如果已经连接,则直接返回实例
 * 否则等待连接
 */
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);
  })
}

处理登录请求(业务层操作)

javascript 复制代码
/**
 * 处理用户登录的路由
 * @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))
    }
})

处理用户登录(数据层)

javascript 复制代码
// 用户登录函数
/**
 * 用户登录
 * @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部署最简单方便,所以就这种方式了,总体就是下面几步

  1. 编写Dockerfile
javascript 复制代码
# 使用官方 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"]
  1. 构建docker镜像
bash 复制代码
docker build -t node-server .
  1. 登录到阿里云镜像服务
  2. 使用docker login xxxx登录到阿里云
  3. 使用docker tag为本地镜像设置别名
  4. 使用docker push推送到阿里云镜像服务器上
  5. 登录到自己的服务器上,使用docker login xxxx登录阿里云
  6. 使用docker pull拉取镜像到本地
  7. 使用docker run -d -p 80:3000 --name node-server xxxxx运行容器,并将3000端口映射到本机的80端口上端口根据具体的需求改

测试

最后请求服务器的接口,测试一下是否正常运行,很幸运,正常返回数据

javascript 复制代码
{
  "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
    }
  }
}

总结

此文主要是简记,总结一下经验,长路漫漫,诸君共勉

相关推荐
极客先躯15 小时前
高级java每日一道面试题-2026年05月03日-实战篇[Docker]-如何实现容器化环境的数据加密?
java·运维·docker·容器·金融·加解密·高级面试
特立独行的猫a15 小时前
鸿蒙PC Node.js三方库移植的AI移植框架与社区贡献完整流程
华为·node.js·harmonyos·三方库移植·鸿蒙pc
AI 编程助手GPT15 小时前
Cursor Router 上线后,我用 Node.js 实现了一个可解释的模型路由器
node.js
ChaITSimpleLove17 小时前
SimpleIdServer 6.0.4 Docker Compose 实战部署指南
运维·docker·容器·身份认证·id-server·simpleidserver
半个落月19 小时前
用 Node.js 搭建 EPUB 问答助手:从文本切片、向量检索到 RAG
人工智能·node.js
程序喵大人19 小时前
【C++进阶】STL容器与迭代器 - 05 map 和 set 为什么按键保持有序
开发语言·c++·容器·迭代器·stl
风曦Kisaki21 小时前
Kubernetes(K8s)笔记Day03: Pod命名空间,标签,Pod 的调度,污点与容忍度,Pod 常见状态和重启策略,Pod 生命周期
linux·运维·笔记·docker·云原生·容器·kubernetes
张忠琳21 小时前
【NVIDIA】NVIDIA k8s-device-plugin v0.19.3 资源管理器模块深度分析之三
云原生·容器·架构·kubernetes·nvidia
meilindehuzi_a21 小时前
Node.js + LangChain.js + Milvus 实战:从 EPUB 入库到《天龙八部》RAG 问答系统
javascript·langchain·node.js
毛驴赶鹿1 天前
低配置服务器怎么搭建监控?Komari Docker部署与公网访问完整教程
运维·服务器·docker