当前位置: 首页 > news >正文

Node.js链接MySql

前言:

        在现代 Web 开发和后端服务中,Node.js 因其高性能和异步特性被广泛使用。MySQL 作为流行的关系型数据库之一,提供了稳定高效的数据存储和管理能力。将 Node.js 与 MySQL 结合,可以构建强大的数据驱动型应用。

一、环境准备

安装必要依赖

npm install express mysql cors jsonwebtoken body-parser

数据库准备

        创建一个名为 demo 的数据库,并添加 user 表: 

CREATE TABLE `user` (`id` int NOT NULL AUTO_INCREMENT,`username` varchar(50) NOT NULL,`password` varchar(100) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

二、核心代码实现

数据库连接配置 (dbconfig.js)

const mysql = require('mysql');// 建立连接池
const pool = mysql.createPool({host: 'localhost',user: 'root',password: 'root',database: 'demo',
})/*** 执行SQL查询的Promise封装* @param {string} sql SQL语句* @param {array} values 参数值* @returns {Promise} 查询结果*/
const query = (sql, values) => {return new Promise((resolve, reject) => {pool.getConnection((err, connection) => {if (err) {console.log('数据库连接错误', err)reject(err)return}connection.query(sql, values, (err, rows) => {if (err) {console.log('SQL执行错误', err)reject(err)return}resolve(rows)connection.release() // 释放连接回连接池})})})
}module.exports = query;

   关键点说明:

  • 使用链接池提高数据库性能,方便后期的统一管理。
  • Promise 封装使异步操作更易管理。 

Express 服务器配置 (server.js)

const express = require('express')
const query = require('./utils/dbconfig')
const cors = require('cors')
const jwt = require('jsonwebtoken')
const bodyParser = require('body-parser')const app = express()
const PORT = 3000;// 安全配置
const JWT_SECRET = 'your-secret-key-here'; // 生产环境应使用环境变量// CORS跨域配置
const corsOptions = {origin: ['http://localhost:5173'], // 允许的前端地址methods: ['GET', 'POST', 'OPTIONS'],allowedHeaders: ['Content-Type', 'Authorization']
}// 中间件
app.use(cors(corsOptions))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))// 启动服务器
app.listen(PORT, () => {console.log(`Server is running on port ${PORT}`)
})

        到这里基本的配置就完成了,现在就可以去完成接口的实现了。

接口实现

登录接口:

app.post('/login', async (req, res) => {try {const { username, password } = req.body;// 参数验证 对请求体中的username和password进行非空检查if (!username || !password) {return res.status(400).json({success: false,message: '用户名和密码不能为空'});}// 数据库查询验证 使用预处理SQL语句查询匹配的用户const sql = 'SELECT * FROM user WHERE username = ? AND password = ?';const users = await query(sql, [username, password]);if (users.length === 0) {return res.status(401).json({success: false,message: '用户名或密码错误'});}const user = users[0];// 使用jsonwebtoken生成访问令牌const token = jwt.sign({ userId: user.id, username: user.username },JWT_SECRET,{ expiresIn: '1h' } // Token有效期1小时);// 返回成功响应res.json({success: true,message: '登录成功',token: token,user: {id: user.id,username: user.username}});} catch (err) {console.error('登录错误:', err);res.status(500).json({success: false,message: '服务器错误'});}
});

         使用Express框架处理POST请求。主要功能包括参数验证、数据库查询、JWT生成和错误处理。

        这边其实在实际项目中像密码这类敏感数据为了安全应该使用哈希存储而非明文查询。

const sql = 'SELECT * FROM user WHERE username = ?';
const users = await query(sql, [username]);
const isValid = await bcrypt.compare(password, users[0].password_hash);
验证:

        到这里就可以来验证我们完成的接口了,这里可以给大家推荐一个VScode中的插件:

        可以看到接口是可以正常运行的,并返回了一个token给我们,这边我写了一个vue的例子,包含了 Vue Router 和  axios的二次封装,这些我在之前的博客都详细的讲过,可以点击对应的文章查看我之前的博客。

        我做了一个简单的登录页面:

<template><div class="login"><h1>Login</h1><form><label for="username">Username:</label><input type="text" id="username" v-model="username"><label for="password">Password:</label><input type="password" id="password" v-model="password"><button type="button" @click="login">Login</button></form></div>
</template><script setup>
import { ref } from 'vue';
import router from '../router';const username = ref('');
const password = ref('');function login() {
}
</script>

axios封装:

// 1.引入axios
import axios from "axios";// 2.创建axios对象
const service = axios.create({baseURL: 'http://localhost:3000'
});// 3.设置请求拦截器 请求前进行一些操作 比如添加请求头、设置loading动画等
service.interceptors.request.use(config => {// 在请求头中添加tokenconst token = localStorage.getItem('token');if (token) {config.headers.Authorization = `Bearer ${token}`;}return config;
}, err => {Promise.reject(error)
})// 4.设置响应拦截器 后端给前端返回数据 可以处理http状态码
service.interceptors.response.use((response) => {if (response.status === 200) {return response.data}},error => {if (error.response) {switch (error.response.status) {case 401:// 处理未授权console.log('请检查账号密码')breakcase 403:// 处理禁止访问console.log('禁止访问')breakcase 404:// 处理未找到console.log('未找到')breakcase 500:// 处理服务器错误console.log('服务器错误')break}}throw error}
)export default service

 模块化:

import request from '../request';// 登录
export function getLogin(userName,password){return request({url: '/login',method: 'post',data: {username: userName,password: password}})
}

        这样我们直接调用这个函数就能发送请求了。 

        在登录页面中导入对应的函数并使用:

import { getLogin } from '../utils/api/users';function login() {getLogin(username.value, password.value).then(res => {if(res.success){// 将token存入localStoragelocalStorage.setItem('token', res.token);// 跳转到首页router.push('/');}}).catch(err => {throw err;});
}

        在路由中配置路由守卫来防止url跳转:

// 配置路由守卫
router.beforeEach((to, from, next) => {const token = localStorage.getItem('token')const isAuthenticated = !!token// 如果路由需要认证但用户未登录if (to.meta.requiresAuth && !isAuthenticated) {return next('/login')}// 如果路由要求未登录(如登录页)但用户已登录if (to.meta.requiresGuest && isAuthenticated) {return next('/home') // 重定向到首页}// 其他情况正常放行next()
})

        这样基本的登录功能就完成了

Token 验证中间件

        在一些请求中需要携带token,否则无法请求到数据,就可以封装一个token验证中间件。

function authenticateToken(req, res, next) {const authHeader = req.headers['authorization'];const token = authHeader && authHeader.split(' ')[1]; // 提取Bearer Tokenif (!token) {return res.status(401).json({success: false,message: '未提供认证Token'});}// 验证Token有效性jwt.verify(token, JWT_SECRET, (err, user) => {if (err) {return res.status(403).json({success: false,message: '无效的Token'});}req.user = user; // 将用户信息附加到请求对象next(); // 继续后续处理});
}

获取用户列表

app.get('/users', authenticateToken, async (req, res) => {try {// 只返回必要字段,不包含密码const sql = 'SELECT id, username FROM user';const users = await query(sql)res.json({success: true,data: users})} catch (err) {console.error('Database error:', err);res.status(500).json({success: false,message: '获取用户列表失败'});}
})

        获取用户列表时就需要在请求头中添加token,在axios的二次封装中,在请求拦截器中就可以在请求头中统一添加token。

service.interceptors.request.use(config => {// 在请求头中添加tokenconst token = localStorage.getItem('token');if (token) {config.headers.Authorization = `Bearer ${token}`;}return config;
}, err => {Promise.reject(error)
})

 模块化:

export function getUsers() {return request({url: '/users',})
}

三、安全最佳实践

  1. 密码存储:实际项目中应使用bcrypt等库进行哈希处理
  2.  环境变量:敏感信息(如数据库密码、JWT密钥)应存储在环境变量中
  3. HTTPS:生产环境必须启用HTTPS
  4. SQL注入防护:始终使用参数化查询
  5. Token安全:设置合理的过期时间,考虑实现刷新Token机制
http://www.lryc.cn/news/592657.html

相关文章:

  • 前端笔记之 async/await 异步编程详解
  • 反射机制的登录系统
  • MyUI会员排名VcMember组件文档
  • Java并发编程痛点解析:从底层原理到实战解决方案
  • Axure RP 10 预览显示“无标题文档”的空白问题探索【护航版】
  • 【密码学】1. 引言
  • vue3引入cesium完整步骤
  • 深入Java注解:从内置到元注解与自定义实战指南
  • STM32-CAN
  • 开发避坑短篇(2):uni-app微信小程序开发‘createIndependentPlugin‘模块缺失问题分析与解决方案
  • 初探:C语言FILE结构之文件描述符与缓冲区的实现原理
  • iOS OC 图片压缩
  • CityEngine自动化建模
  • Java面试宝典:Maven
  • 片上网络(NoC)拓扑结构比较
  • 现代R语言机器学习:Tidymodel/Tidyverse语法+回归/树模型/集成学习/SVM/深度学习/降维/聚类分类与科研绘图可视化
  • PHP:经典与现代交融的Web开发利器
  • 生成式引擎优化(GEO)核心解析:下一代搜索技术的演进与落地策略
  • 超简单linux上部署Apache
  • UDP协议介绍
  • 深入理解Linux文件操作:stdin/stdout/stderr与C语言文件函数全解析
  • IDEA 2020.1版本起下载JDK
  • 基于 Docker 及 Kubernetes 部署 vLLM:开启机器学习模型服务的新篇章
  • Docker --privileged 命令详解
  • Jenkins+Docker+Git实现自动化CI/CD
  • [2025CVPR-目标检测方向]FSHNet:一种用于3D物体检测的全稀疏混合网络。
  • vue2 面试题及详细答案150道(41 - 60)
  • Linux系统安装Docker及部署Node.js 20.15.0(含pnpm、pm2)完整指南
  • 武汉江滩某码头变形及应力自动化监测
  • 由于热爱,我选PGCE专家学习