Heroku部署的Node应用无法连接MongoDB Atlas数据库(粘贴连接串仍报错)
问题描述
我目前在连接部署在cloud.mongodb.com上的MongoDB数据库时遇到问题:网页可以正常加载,但只要尝试访问MongoDB数据库,应用就会崩溃。
本地运行Node应用时可以正常连接该数据库,但切换到Heroku上的部署版本后就会抛出如下错误:
MongoNetworkError: failed to connect to server [cluster0-shard-00-01.32gri.mongodb.net:27017] on first connect [MongoNetworkTimeoutError: connection timed out
我已经将实际的数据库连接串直接写在代码中(甚至没有使用环境变量),但仍然无法正常连接。我的Procfile内容如下:web: node app.js,package.json内容如下:
{ "name": "mortagewebsite", "version": "1.0.0", "description": "Shows details about our customers and how close they are to get a mortgage.", "main": "app.js", "scripts": { "start": "node app.js" }, "repository": { "type": "git", "url": "git+https://github.com/kdonthi/MortgageHelper.git" }, "author": "Kaushik Donthi", "license": "ISC", "bugs": { "url": "https://github.com/kdonthi/MortgageHelper/issues" }, "homepage": "https://github.com/kdonthi/MortgageHelper#readme", "dependencies": { "express": "^4.17.1", "joi": "^17.4.2", "mongoose": "^5.13.7", "serve": "^12.0.0", "winston": "^3.3.3" }, "devDependencies": { "jest": "^27.0.6" }, "engines": { "node": "16.6.2" } }
数据库连接代码如下(我已经将PASSWORD和DBNAME替换为正确的值):
let db = process.env.db || "mongodb+srv://kaushikdr:PASSWORD@cluster0.32gri.mongodb.net/DBNAME?retryWrites=true&w=majority" mongoose.connect(db) .then(_ => console.log("Connected to database."));
应用在触发如下路由时出现异常(Person是我在Mongoose中使用的模型):
app.get("/people/count", (req, res) => { let filter = req.body.filter ? req.body.filter : {}; getPeopleCount(res, filter); }) function getPeopleCount(res, filter) { Person.countDocuments(filter, (error, documentCount) => { if (error) { winston.info(error); res.status(404).send(error); } else { res.send(documentCount.toString()); } }) }
恳请各位帮忙排查问题原因,多谢!
排查解决方案
- 优先检查MongoDB Atlas的IP白名单配置。Atlas默认仅允许白名单内的IP访问数据库,你本地IP已经加入白名单所以可以正常连接,Heroku应用的出口IP没有被加入白名单就会触发连接超时。测试环境可以临时配置允许所有IP访问(0.0.0.0/0)验证是否是这个问题,生产环境建议获取Heroku的固定出口IP段加入白名单,或者通过私有网络对接功能打通两者的网络。
- 补充数据库连接的错误捕获逻辑。你当前的mongoose连接代码仅处理了成功场景,没有捕获连接失败的错误,出现异常时会直接抛出未捕获错误导致应用崩溃,调整代码如下:
mongoose.connect(db, { connectTimeoutMS: 10000, // 10秒连接超时 socketTimeoutMS: 45000 // 45秒socket超时 }) .then(_ => console.log("Connected to database.")) .catch(err => console.error("Database connection failed: ", err));
- 确认Heroku应用的出站规则。检查你的Heroku账号是否配置了特殊的网络限制,阻止了27017、27015等MongoDB默认通信端口的出站请求。
- 不要硬编码数据库连接串在代码中。当前你把包含密码的连接串直接写在代码里的操作存在严重的安全风险,后续调整为通过Heroku的环境变量存储这类敏感信息,不要把敏感内容提交到代码仓库。
内容的提问来源于stack exchange,提问作者Alaska
相关产品推荐
相关产品推荐

