Node.js+Express连接MongoDB的重复查询与连接控制问题
问题解决:Node.js + Express + MongoDB 连接相关问题
核心问题梳理
- 服务启动时自动连接MongoDB,期望仅在触发连接的Fetch请求时建立连接
- 点击触发Fetch的按钮时出现
TypeError: Failed to fetch错误,但连接/断开操作实际正常执行 - 断开数据库连接后访问数据库会触发
MongoNotConnectedError,导致服务崩溃,需仅输出错误并保持服务运行 - 历史问题:重复POST查询无法连接数据库,需重启服务
问题逐个解决
1. 取消服务启动自动连接,改为按需连接
原connect.js中直接调用stconnect()导致服务启动即连接Mongo。修改方式:
- 删除
connect.js末尾的stconnect().then(...)代码块 - 仅在收到
/login请求时调用连接方法
2. 修复TypeError: Failed to fetch错误
该错误源于后端接口未返回响应,导致Fetch请求无结果超时,同时需解决跨域问题:
- 每个接口添加明确的响应返回(
res.send()/res.status()) - 添加CORS中间件解决跨域(前端与后端端口不同时必须)
3. 捕获MongoNotConnectedError,避免服务崩溃
所有数据库操作包裹在try/catch中,添加连接状态检查,同时配置全局错误处理:
- 在数据库查询前检查连接状态
- 新增全局错误处理中间件捕获未处理异常
- 在连接模块中添加连接状态判断方法
修改后的完整代码
connect.js
const { MongoClient } = require('mongodb'); const url = 'mongodb://127.0.0.1:27017/'; let client; let dbname = 'College'; let db; async function stconnect() { // 避免重复创建连接 if (client && client.isConnected()) { return db; } client = new MongoClient(url); await client.connect(); db = client.db(dbname); return db; } const getdb = () => db; // 新增连接状态检查方法 const isConnected = () => client && client.isConnected(); async function disconnect() { if (client && client.isConnected()) { await client.close(); db = null; client = null; } } module.exports = { stconnect, getdb, disconnect, isConnected };
accessdb.js
const conn = require('./connect'); // 确保路径与实际文件结构匹配 async function getdata(data, res) { let html = "<html> <head> </head> <body> <table>"; try { // 先检查数据库连接状态 if (!conn.isConnected()) { throw new Error("数据库未连接,请先点击连接按钮"); } const db = conn.getdb(); const collection = db.collection('Students'); const file = await collection.find({ "Department": data }).toArray(); for(let i = 0; i < file.length; i++){ html += `<tr> <td> ${file[i].Name}</td><td>${file[i].Department}</td><td>${file[i].Semester}</td></tr>`; console.log(`文件:${file[i].Name}`); } html += "</table></body></html>"; res.send(html); } catch(e) { console.error("数据库操作错误:", e); // 返回错误提示页面 res.status(500).send(`<html><body>操作失败:${e.message}</body></html>`); } } async function getconnection() { try { await conn.stconnect(); console.log("数据库连接成功"); } catch(err) { console.error("连接失败:", err); throw err; } } async function removeconnection() { try { await conn.disconnect(); console.log("数据库断开成功"); } catch(err) { console.error("断开失败:", err); throw err; } } module.exports = { getdata, getconnection, removeconnection };
Server.js
const express = require('express'); const app = express(); const bodyParser = require('body-parser'); const cors = require('cors'); // 解决跨域,需先安装:npm install cors let Util = require('./files/modules/acessdb'); // 启用CORS解决跨域问题 app.use(cors()); app.use(bodyParser.urlencoded({extended:false})); app.use(bodyParser.json()); app.get('/',(req,res)=>{ res.send("服务运行中"); }); app.post('/getinput', async (req,res)=>{ console.log("查询参数:"+req.body.depart); await Util.getdata(req.body.depart,res); }); app.get('/login', async (req,res)=>{ console.log("触发连接请求"); try { await Util.getconnection(); res.status(200).send("连接成功"); } catch(err) { res.status(500).send("连接失败:" + err.message); } }); app.get('/disconnect', async (req,res)=>{ console.log("触发断开请求"); try { await Util.removeconnection(); res.status(200).send("断开成功"); } catch(err) { res.status(500).send("断开失败:" + err.message); } }); // 全局错误处理中间件,防止服务崩溃 app.use((err, req, res, next) => { console.error("全局捕获错误:", err); res.status(500).send("服务器内部错误"); }); const server = app.listen(8000,()=>{ let host=server.address().address; let port = server.address().port; console.log("服务运行在 "+host+":"+port); });
前端Fetch代码修改
const con = document.getElementById("con"); // 确保元素ID与页面一致 con.addEventListener('click', async e=>{ console.log("连接按钮点击"); try { const response = await fetch('http://localhost:8000/login',{method:'GET'}); if(response.ok){ const msg = await response.text(); console.log(msg); document.getElementById("status").value = "已连接"; } else { const errMsg = await response.text(); throw new Error(errMsg); } } catch(error){ console.log("连接失败:", error.message); document.getElementById("status").value = "连接失败"; } }); const discon = document.getElementById("ddb"); discon.addEventListener('click', async e=>{ console.log("断开按钮点击"); try { const response = await fetch('http://localhost:8000/disconnect',{method:'GET'}); if(response.ok){ const msg = await response.text(); console.log(msg); alert("已断开连接"); document.getElementById("status").value = "已断开"; } else { const errMsg = await response.text(); throw new Error(errMsg); } } catch(error){ console.log("断开失败:", error.message); document.getElementById("status").value = "断开失败"; } });
关键说明
- 连接复用:连接模块新增重复连接检查,解决重复POST无法连接的问题,同时提升性能
- 错误闭环:所有异步操作添加try/catch,全局错误中间件确保服务不会因未捕获异常崩溃
- 响应完整性:每个接口都返回明确的状态码和响应内容,彻底解决Fetch无响应报错
- 跨域处理:通过CORS中间件解决前后端跨域请求限制
内容的提问来源于stack exchange,提问作者JustaNobody
相关产品推荐
相关产品推荐

