离线启动Node服务报querySrv ECONNREFUSED,目标连接本地MongoDB
问题现象
开发Node.js+MongoDB项目时遇到启动异常,报错日志如下:
MongoDB connected... Development server live on http://localhost:3000 node:internal/errors:465 ErrorCaptureStackTrace(err); ^ Error: querySrv ECONNREFUSED _mongodb._tcp.auctiondbcluster.s6rzg.mongodb.net at QueryReqWrap.onresolve [as oncomplete] (node:dns:213:19) { errno: undefined, code: 'ECONNREFUSED', syscall: 'querySrv', hostname: '_mongodb._tcp.auctiondbcluster.s6rzg.mongodb.net' }
异常触发规律:
- 设备连接WiFi时服务可正常运行
- 设备离线状态启动服务必现上述错误
- 开发环境预期连接本地MongoDB实例,地址为
mongodb://localhost:27017/auctionDB,未主动配置连接MongoDB线上集群 - 已确认
.env文件中NODE_ENV参数值为development
现有代码逻辑
服务启动逻辑(app.js):
const runServer = async () =>{ if(process.env.NODE_ENV !== "production"){ await connectDb(process.env.MONGODB_LOCAL_CONNECTION); app.listen(PORT, ()=>{ console.log(`Development server live on http://localhost:${PORT}`); }) } else { await connectDb(process.env.MONGODB_CONNECTION_STRING); app.listen(PORT, ()=>{ console.log(`Production server live on port ${PORT}`); }) } } runServer();
数据库连接逻辑(connectDb.js):
const mongoose = require("mongoose"); /** * @description: Connect to the database by providing the connection string. * @param {String} uri | MongoDB URI * @default: mongodb://localhost:27017/auctionDB * * @returns {undefined} */ const connectDb = (url = process.env.MONGODB_LOCAL_CONNECTION) => { try { const con = mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }); if(con) console.log("MongoDB connected...") } catch(e){ console.log(`Error: ${e}`); } }; module.exports = connectDb;
排查方向与修复方案
1. 先修复数据库连接的异步逻辑bug
现有connectDb逻辑存在严重的异步写法错误,是导致异常抛出不符合预期的核心原因:
mongoose.connect返回Promise对象,现有代码没有加await等待连接完成,try/catch只能捕获同步错误,无法捕获异步连接失败的异常,错误会直接抛到全局导致进程崩溃- 直接判断
if(con)时,con是pending状态的Promise对象,永远为真值,会在连接还没建立完成时就提前打印MongoDB connected...日志,误导判断
修复后的连接代码:
const mongoose = require("mongoose"); const connectDb = async (url = process.env.MONGODB_LOCAL_CONNECTION) => { try { await mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }); console.log("MongoDB connected...") } catch(e){ console.log(`MongoDB connection failed: ${e.message}`); process.exit(1); } }; module.exports = connectDb;
2. 排查环境变量加载问题
报错中明确出现了线上MongoDB集群的SRV解析地址,说明代码实际拿到的连接串不是预期的本地地址,按以下顺序排查:
- 确认
dotenv加载位置正确:必须在app.js最顶部、所有业务代码/数据库相关代码引入之前执行require('dotenv').config(),否则.env中配置的变量不会被注入到process.env中,代码会读取系统全局环境变量的值 - 加调试日志确认连接串:在调用
connectDb前打印console.log('Current MongoDB URI:', process.env.MONGODB_LOCAL_CONNECTION),如果输出是mongodb+srv://开头的线上地址,检查:.env文件中变量名是否拼写正确,是否误把本地连接串变量写成了生产环境的MONGODB_CONNECTION_STRING.env文件中变量值是否误填为线上集群地址,值两边不要加多余的引号- 系统全局环境变量中是否配置过
MONGODB_CONNECTION_STRING为线上地址,导致环境变量串用
3. 排查多余的连接逻辑
全局搜索项目代码中两个关键词:
mongodb+srv://:确认没有地方硬编码线上集群连接串mongoose.connect:确认除了connectDb.js外,没有其他文件(比如模型文件、路由文件、第三方引入的工具文件)偷偷调用连接方法初始化线上连接
4. 本地服务与依赖缓存排查
- 离线状态下先在终端执行
mongosh,确认本地MongoDB服务处于正常启动状态,能正常连通 - 如果之前测试过线上集群连接,低版本mongoose可能存在连接配置缓存问题,可以删除
node_modules目录和lock文件后重新安装依赖,清除缓存 - 连WiFi时服务正常是因为DNS可以正常解析线上集群域名,如果代码误连了线上地址,WiFi环境下能建立连接所以不报错,离线时DNS解析失败直接抛错,和这个现象完全匹配。
内容的提问来源于stack exchange,提问作者HarshitRV
相关产品推荐
相关产品推荐

