Node.js与Express连接MySQL实现登录注册功能详解

作者:夜航船

时间:2026-10-22

浏览:147

本文介绍使用Node.js和Express框架搭建后端,结合MySQL数据库实现用户登录与注册功能。重点解析异步查询中Promise的应用、Session会话状态管理以及中文乱码问题的解决,并展望了后续文章页渲染的技术选型。

文章目录

项目背景与技术选型

为了完成数据库课程设计,后端计划采用Node.js进行搭建,前端则使用Vue开发一个博客系统(近期正在学习相关技术)。起初考虑不使用框架以夯实基础,但由于需要在三周内完成项目并应对多项考试,最终选择了Express框架,这显著降低了开发和学习成本。

数据库方面选择了较为规范的MySQL,其代码复杂度高于MongoDB。鉴于这是数据库课程作业,若使用MongoDB可能因未涉及主键、外键等设置而被判定不合格,因此必须使用关系型数据库。

后端服务初始化与入口配置

首先在主入口JS文件中引入处理登录注册业务的模块,并启动服务监听指定端口。

Express路由与静态资源配置


var express = require('express');
var user = require('./controll/user'); 

var app = new express();

app.use(express.static('public')); //静态资源的入口
app.use('/user',user);    //这样写是为了以后如果改变了请求路径,也不用改逻辑js而是改这行的路径即可

var server = app.listen(3000)

前端交互与AJAX请求实现

前端HTML页面结构如下:

用户登录与注册前端逻辑


$("#signup").click(function(){
  $.ajax({
   url: "/user/signup",
   type: 'post',
   data: $("#formid").serialize(),
   success: function(data) {
    if(data.status == 99999) {
     alert("3秒后跳转到首页");
     setTimeout(function() {
      location.href='http://'+window.location.host+'/html/index.html';
     },3000)
    }else {
     alert('登录名或密码错误')
    }
   }
  })  
 })


 $("#register").click(function(){
  $.ajax({
   url: "/user/register",
   type: 'post',
   data: $("#formRegister").serialize(),
   success: function(data) {
    console.log(data);
    if(data.status == 99999) {
     alert("注册成功")
    }else {
     alert("登录名已经有人用")
    }
   }
  })  
 })

后端核心逻辑与异步处理

后端user.js模块代码较多,此处不再逐一解释,若后续有空隙再补充说明。主要关注以下几个关键点:

MySQL连接封装与Session管理


var mysql = require('mysql');
var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('cookie-session');

function select(sql) {
 var promise = new Promise(function(resolve,reject) {
  var result = null;
  var mysql = require('mysql');
  var connection = mysql.createConnection({
   host: 'localhost',
   user: 'root',
   password: 'root'
  });

  connection.connect();
  connection.query("USE test");
  connection.query(sql, function (err, results, fields) { 
   if (err) { 
    console.log("err");
    reject(err); 
   }else {
    console.log("yes");
    if(results.length > 0) {
     resolve({status: 99999});
    }else {
     resolve({status: 00000});
    }   
   } 
   } 
  );
  connection.end(); 
 })

 return promise; 
}


var router = express.Router();
router.use(bodyParser.urlencoded({ extended: true }));
router.use(cookieParser())
router.use(session({
 secret: 'blog'
}))
router.use(function timeLog(req,res,next) {
 var _user = req.session.user;
 if(_user) {
  //router.locals.user = user;
 }
 next();
})

//登录
router.post('/signup',function(req, res) {
 var _user = req.body.user;
 var name = _user.name;
 var password = _user.password;
 select('SELECT * FROM name WHERE name = "'+ name + '" AND password = "' + password + '";').then(function(data) {
  //session存user name和userid
  req.session.user = name;
  data.status > 50 ? data.url = '/html/index.html' : null;
  res.json(data);
  res.end();
  req.redirect("/");
 }).catch(function(err){})

})

//注册
router.post('/register',function(req, res) {
 var _user = req.body.user;
 var name = _user.name;
 var password = _user.password;
 console.log(name+"  "+password)
 select('SELECT * FROM name WHERE name = "'+ name + '";')
  .then(function(data) {
   if(data.status == 99999) {
    console.log("已有此用户名")
    res.json({status:00000});
    res.end();
   }else {
    select('INSERT INTO name(name,password) VALUES ("'+name+'", "'+password+'");')
    .then(function(data) { 
     res.json({status:99999});
     res.end();
    }).catch(function(err){})
   }   
  }).catch(function(err){

  })

});

//退出
router.get("/logout",function(req, res) {
 delete req.session.user;
 res.end();
})

//获取session
router.get("/session",function(req, res) {
 console.log("user in session");
 console.log(req.session.user);
 res.json({user:req.session.user});
 res.end();
})

module.exports = router;

代码很多,不一一解释了,如果以后有空再补回。先说几个点

  1. 数据库连接逻辑封装在select方法中。由于需要返回查询结果,必须使用return,但数据库查询是异步操作,直接在select函数末尾return无效。因此,return语句需置于查询完成的回调函数中,但回调函数内的return无法直接返回给select函数外部。解决方案是采用ES6的Promise机制,具体细节建议参考相关文档深入学习。
  2. 获取查询结果后,需明确登录与注册的逻辑分支,区分成功与失败的情况。在注册环节曾遇到误区:由于用户名不能重复,需先查询数据库,若存在则返回status=99999。起初对Promise理解不足,误以为查询失败会触发reject(err),实际上查询无结果时返回空数组[],仍执行resolve(),因此需通过返回的status值来区分业务状态。
  3. 关于保存登录状态,即Session机制,目前理解尚不深入。此步骤可置于router的中间件中执行,使得经过该router的请求均能执行相应逻辑。若存在req.session.user,则将当前locals.user进行赋值。
  4. 注册功能调试耗时较长,除对Promise理解不透彻外,还涉及MySQL不支持中文输入的问题。当时未设置utf8编码,导致报错并进入reject(err)分支。不仅需将MySQL语言设置为utf8,还需注意在Navicat新建属性时字符类型的设置,否则字符集冲突会导致插入语句失败。

后续功能规划与技术展望

最后,对项目的未来展望进行简要说明。

文章页面计划采用Jade模板引擎渲染整个HTML后返回。考虑到文章内容变动较少,且Vue更适合处理如评论等小组件,而文章主体多为静态内容,因此采用后端直接渲染返回的方式,避免额外的请求与渲染开销。

结合当前进度与能力,除文章的增删改查功能外,博客主要提供查看和评论文章的功能。对于Vue的具体应用场景尚不明确,可能因对vue-router等模块接触和理解不够深入。预计主要功能为实现一个简洁版的Markdown编辑器。

以上为本文的全部内容,希望对读者的学习有所帮助,也欢迎大家继续支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章