Express+MongoDB项目users.findOne()缓冲超时错误排查求助
users.findOne() buffering timed out after 10000ms) 项目分为client(React)和server(Express)两个目录,server通过nodemon启动后控制台显示已成功连接MongoDB Atlas,client的React服务也正常运行,但调用注册/登录API时,users.findOne()执行超时,报错{error: "Operation users.findOne() buffering timed out after 10000ms"}并进入catch块。该项目之前在其他系统和目录结构下可正常运行,已删除旧库并创建新库。
相关代码
db.js
require('dotenv').config(); const mongoose = require('mongoose'); mongoose.set('strictQuery', true); const mongoURI = process.env.MONGO_URI; // Connecting to MongoDB Atlas through Mongo URI const connectToMongo = () => { mongoose.connect(mongoURI, () => { console.log('Connected to Mongoose Successfully'); }) } module.exports = connectToMongo;
index.js
const connectToMongo = require('./db'); const express = require('express'); const cors = require('cors'); require('dotenv').config(); // calling db.js to connect to MongoDB connectToMongo(); const app = express() const port = 5000; // midleware to use API Endpoints app.use(express.json()); app.use(cors()); //Available Routes app.use('/api/auth', require('./Routes/auth')); app.use('/api/notes', require('./Routes/notes')) app.listen(port, () => { console.log(`iNotebook listening at http://localhost:${port}`) })
/createUser 路由
// Route 1: Create a user using: POST api/auth/createUser. No Login Required. router.post('/createUser', body('name').isLength({ min: 3 }), body('email').isEmail(), body('password').isLength({ min: 8 }), async (req, res) => { let success = false; //if there is error, return bad rquest and errors const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ success, errors: errors.array() }); } try { //check whether the user with this email exists already // console.log(req.body.email); let user = await User.findOne({ email: req.body.email }); //if yes, through an error if (user) { return res.status(400).json({ success, error: "A user with this email already exist" }); } //hashing password const salt = await bcrypt.genSalt(10); const safePass = await bcrypt.hash(req.body.password, salt); //if not exist already, create a new user user = await User.create({ name: req.body.name, email: req.body.email, password: safePass }) //generate an Authentication Token and return it as a response const data = { user: { id: user.id } } const authToken = jwt.sign(data, JWT_Secret); success = true; res.json({ success, authToken }); } catch (error) { console.error(error.message); res.status(500).send({"error": error.message}); } } );
/loginUser 路由
// Route 2: Authenticate a user using: POST api/auth/loginUser. No Login Required. router.post('/loginUser', body('email', 'Enter a valid Email').isEmail(), body('password', 'Password cannot be blank').exists(), async (req, res) => { let success = false; //if there is error, return bad rquest and errors const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({success, errors: errors.array() }); } const { email, password } = req.body; try { //check whether user with this email exist or not let user = await User.findOne({ email }); //if not, through an error if (!user) { return res.status(400).json({success, error: "Please try to login with correct credentials" }); } //if exist, compare the entered password const passCompare = await bcrypt.compare(password, user.password); //if do not match, through an error if (!passCompare) { return res.status(400).json({success, error: "Please try to login with correct credentials" }); } //if matched, generate an Authentication Token as a response const data = { user: { id: user.id } } // res.send(user.id) const authToken = jwt.sign(data, JWT_Secret); success = true; res.status(200).json({success, authToken }); console.log(res.status(200).json({success, authToken })) } catch (error) { console.error(error.message); res.status(500).send("Internal error occured"); } } );
MongoURI示例:"mongodb+srv://haseeb-sheikh10:<password>@inotebook-cluster.dbrzmnx.mongodb.net/inotebook/?retryWrites=true"
解决方案
1. 修复MongoDB连接的错误处理
当前db.js中的mongoose.connect仅监听成功回调,未处理连接失败场景,控制台打印的"Connected to Mongoose Successfully"可能是假阳性——实际连接未成功,但回调仍执行。
修改db.js为异步方式,正确处理连接状态:
require('dotenv').config(); const mongoose = require('mongoose'); mongoose.set('strictQuery', true); const mongoURI = process.env.MONGO_URI; const connectToMongo = async () => { try { await mongoose.connect(mongoURI); console.log('Connected to Mongoose Successfully'); } catch (err) { console.error('MongoDB连接失败:', err.message); process.exit(1); // 连接失败时退出进程,避免服务空转 } } module.exports = connectToMongo;
同时修改index.js,等待数据库连接成功后再启动Express服务:
const connectToMongo = require('./db'); const express = require('express'); const cors = require('cors'); require('dotenv').config(); const app = express() const port = 5000; app.use(express.json()); app.use(cors()); app.use('/api/auth', require('./Routes/auth')); app.use('/api/notes', require('./Routes/notes')); // 等待数据库连接成功后再启动服务 const startServer = async () => { try { await connectToMongo(); app.listen(port, () => { console.log(`iNotebook listening at http://localhost:${port}`); }); } catch (err) { console.error('服务启动失败:', err.message); } } startServer();
2. 检查MongoDB Atlas的网络访问权限
登录MongoDB Atlas控制台,进入目标集群 -> Network Access,确认当前服务器/本地IP已加入白名单,或临时设置为允许所有IP(0.0.0.0/0)用于测试。
3. 验证MongoURI的正确性
确保.env文件中的MONGO_URI已替换<password>为真实数据库密码,且数据库名称(inotebook)在Atlas中已存在。
4. 明确指定数据库名称(可选)
若Mongoose版本较新,可在连接时添加dbName参数明确指定数据库:
await mongoose.connect(mongoURI, { dbName: 'inotebook' });
内容的提问来源于stack exchange,提问作者Haseeb Irfan

