部署Node.js到Heroku时遭遇MongoNotConnectedError问题求助
我做了一个React前端、Express Node.js后端(搭配Mongoose与MongoDB)的项目,本地运行正常,但构建后部署到Heroku时出现应用错误。
后端连接代码
require('dotenv').config(); const express = require('express') const session = require("express-session") const bodyParser = require('body-parser') const cors = require('cors') const zomatoRoutes = require('./Routes/zomato') const paymentRoutes = require('./Routes/payments') const mongoose = require('mongoose') const passport = require("passport") const MongoStore = require('connect-mongo'); const uri = process.env.MONGO_URI || 'mongodb://localhost/zomato'; console.log(uri,'this is the mongo Atlas uri if connected using that !!!') const options = { useNewUrlParser: true, useUnifiedTopology: true, dbName:'zomato1' } const connectDB = async () => { await mongoose.connect(uri, options ).then(() => { console.log('mongo connected') }).catch( e => console.log(e)) } connectDB().then(() => { app.listen( process.env.PORT ||5252 , () => { console.log("express app is up and running on port 5252"); }) })
Mongo会话存储配置
app.use(session({ secret: "this is unambigous secret", resave: false, saveUninitialized: false, cookie: { maxAge: 24*60*60*1000 }, store : MongoStore.create({ client: mongoose.connection.getClient(), dbName:'zomato1', ttl: 14 * 24 * 60 * 60 }) })); app.use(passport.initialize()); app.use(passport.session());
部署错误日志
执行git push heroku master:main部署时,出现MongoNotConnectedError: MongoClient must be connected to perform this operation错误,完整日志如下:
mongodb+srv://vishal_torne_22:********@db-first-hernode.zu6btrs.mongodb.net/<DBNamecomeshere>?retryWrites=true&w=majority this is the mongo Atlas uri if connected using that !!! 2022-07-31T11:19:34.581869+00:00 app[web.1]: /app/node_modules/mongodb/lib/utils.js:367 2022-07-31T11:19:34.581876+00:00 app[web.1]: throw new error_1.MongoNotConnectedError('MongoClient must be connected to perform this operation'); 2022-07-31T11:19:34.581877+00:00 app[web.1]: ^ 2022-07-31T11:19:34.581877+00:00 app[web.1]: 2022-07-31T11:19:34.581878+00:00 app[web.1]: MongoNotConnectedError: MongoClient must be connected to perform this operation 2022-07-31T11:19:34.581878+00:00 app[web.1]: at getTopology (/app/node_modules/mongodb/lib/utils.js:367:11) 2022-07-31T11:19:34.581881+00:00 app[web.1]: at Collection.createIndex (/app/node_modules/mongodb/lib/collection.js:258:82) 2022-07-31T11:19:34.581881+00:00 app[web.1]: at MongoStore.setAutoRemove (/app/node_modules/connect-mongo/build/main/lib/MongoStore.js:147:35) 2022-07-31T11:19:34.581881+00:00 app[web.1]: at /app/node_modules/connect-mongo/build/main/lib/MongoStore.js:128:24 2022-07-31T11:19:34.581882+00:00 app[web.1]: at processTicksAndRejections (node:internal/process/task_queues:96:5) 2022-07-31T11:19:34.581882+00:00 app[web.1]: 2022-07-31T11:19:34.581882+00:00 app[web.1]: Node.js v17.9.1 2022-07-31T11:19:34.703486+00:00 heroku[web.1]: Process exited with status 1 2022-07-31T11:19:34.791551+00:00 heroku[web.1]: State changed from starting to crashed
疑问与已尝试方法
疑问
- Heroku 20栈是否必须使用MongoClient?
- 为何本地正常的Mongoose.connect()部署后会报错?
已尝试的解决方法
- 在MongoDB Atlas中添加白名单0.0.0.0/0(包含当前IP)
- 将Mongoose连接代码改为异步,确保先连接数据库再启动服务
- 修改package.json中的引擎版本以适配Heroku:
{ "version": "1.0.0", "engines": { "node": "17.x", "npm":"8.x" } }
问题根源
错误出在MongoStore初始化时机过早——你在Mongoose完成数据库连接之前就创建了MongoStore实例,此时mongoose.connection.getClient()返回的客户端还未建立连接,导致MongoStore尝试操作数据库时触发MongoNotConnectedError。
本地运行正常是因为本地数据库连接速度快,可能在MongoStore初始化前连接已完成;但Heroku环境下网络延迟更高,连接建立速度慢,就暴露了这个时序问题。另外,Heroku 20栈并没有强制要求使用MongoClient,问题和栈版本无关。
修复步骤
调整MongoStore的初始化时机
不要在全局直接创建MongoStore,而是等Mongoose连接完成后再初始化session中间件:// 先定义app和其他基础中间件 const app = express(); app.use(bodyParser.json()); app.use(cors()); // ...其他非session相关中间件 const connectDB = async () => { try { await mongoose.connect(uri, options); console.log('mongo connected'); // 连接成功后再初始化session和MongoStore app.use(session({ secret: "this is unambigous secret", resave: false, saveUninitialized: false, cookie: { maxAge: 24*60*60*1000 }, store: MongoStore.create({ client: mongoose.connection.getClient(), dbName:'zomato1', ttl: 14 * 24 * 60 * 60 }) })); app.use(passport.initialize()); app.use(passport.session()); // 挂载路由 app.use('/api', zomatoRoutes); app.use('/api', paymentRoutes); // 启动服务 app.listen(process.env.PORT || 5252, () => { console.log(`express app is up and running on port ${process.env.PORT || 5252}`); }); } catch (e) { console.error('MongoDB连接失败:', e); process.exit(1); } }; connectDB();优化Mongoose连接逻辑
你的connectDB函数混用了await和.then(),统一改为try/catch写法,更清晰且便于错误处理。验证Heroku环境变量
确保Heroku的环境变量MONGO_URI正确配置,且URI中的数据库名称和dbName参数一致(你的URI里写了<DBNamecomeshere>,需要替换为实际的数据库名zomato1)。
额外建议
- 避免在Heroku使用Node.js 17.x版本,该版本属于不稳定版本,建议切换到LTS版本(比如16.x),减少兼容性问题:
"engines": { "node": "16.x", "npm": "8.x" } - 在MongoDB Atlas中,建议只添加Heroku的出站IP段或使用VPC peering,而不是直接开放0.0.0.0/0,提升安全性。
内容的提问来源于stack exchange,提问作者Vishal Torne

