You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js+Express连接MongoDB的重复查询与连接控制问题

问题解决:Node.js + Express + MongoDB 连接相关问题

核心问题梳理

  1. 服务启动时自动连接MongoDB,期望仅在触发连接的Fetch请求时建立连接
  2. 点击触发Fetch的按钮时出现TypeError: Failed to fetch错误,但连接/断开操作实际正常执行
  3. 断开数据库连接后访问数据库会触发MongoNotConnectedError,导致服务崩溃,需仅输出错误并保持服务运行
  4. 历史问题:重复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 = "断开失败";
    }
});

关键说明

  1. 连接复用:连接模块新增重复连接检查,解决重复POST无法连接的问题,同时提升性能
  2. 错误闭环:所有异步操作添加try/catch,全局错误中间件确保服务不会因未捕获异常崩溃
  3. 响应完整性:每个接口都返回明确的状态码和响应内容,彻底解决Fetch无响应报错
  4. 跨域处理:通过CORS中间件解决前后端跨域请求限制

内容的提问来源于stack exchange,提问作者JustaNobody

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 03:25:11