Node.js应用中Tunnel-SSH无法连接MongoDB云服务器求助
解决Node.js中使用tunnel-ssh连接MongoDB云服务器的两个问题
嘿,我来帮你搞定这两个头疼的问题,咱们一步步拆解分析:
问题1:隧道建立后_connections: 0,无法确认连接状态
首先给你吃个定心丸:这个_connections: 0是正常现象!它代表的是当前通过这个SSH隧道服务建立的活跃连接数——你刚启动隧道,还没发起MongoDB请求,自然没有活跃连接,所以值为0,不代表隧道没建立成功。
验证隧道是否真的正常工作的方法:
- 用命令行工具测试本地端口:打开终端执行
telnet 127.0.0.1 27000或者nc -zv 127.0.0.1 27000,如果能收到“连接成功”的提示,说明隧道已经在本地监听端口了。 - 查看云服务器上的MongoDB日志:登录服务器,找到MongoDB的日志文件(通常是
/var/log/mongodb/mongod.log),如果隧道建立后有来自127.0.0.1的连接请求(因为你配置的dstHost是服务器本地的127.0.0.1),说明转发是正常的。 - 加个明确的启动日志:在tunnel的回调里打印一句
console.log("SSH隧道已成功启动,可以发起MongoDB请求了"),这样你就能清晰知道什么时候可以调用数据库函数了。
问题2:调用getDataFromMongoDB时返回EADDRINUSE: address already in use 127.0.0.1:27000
这个错误有两个核心原因,咱们逐个解决:
1. 最关键的错误:MongoDB连接URI写错了!
你的隧道配置是把本地27000端口转发到云服务器的27017端口,但你的代码里MongoDB连接字符串用的是localhost:27017——这相当于直接连接你本地机器的MongoDB(如果本地没装,就连不上;如果装了,也和云服务器没关系)。
修正后的URI应该指向本地的隧道端口27000:
const uri = "mongodb://USRNAME:PASSWORD_FOR_MONGDB_DATABASE@localhost:27000";
2. 本地27000端口被占用
如果修正URI后还是报这个错,那就是有其他进程在占用27000端口:
- Windows:打开命令提示符,执行
netstat -ano | findstr :27000找到占用端口的PID,然后用taskkill /PID <你的PID> /F强制杀死进程。 - Linux/macOS:执行
lsof -i :27000找到进程,再用kill -9 <你的PID>杀死。 - 或者换个端口:把config里的
localPort改成27018之类的未被占用的端口,记得同步修改MongoDB连接URI里的端口。
3. 添加隧道关闭逻辑,避免端口泄漏
之前的代码没有关闭隧道的逻辑,导致程序退出后端口可能被残留进程占用。可以在获取数据后手动关闭,或者监听程序退出信号:
// 在getDataFromMongoDB函数的finally块里关闭隧道和MongoDB连接 async function getDataFromMongoDB(tunnel) { // ... 原有代码 ... finally { await client2.close(); tunnel.close(); console.log("MongoDB连接和SSH隧道已关闭"); } } // 监听程序退出信号,确保异常退出时也关闭隧道 process.on('SIGINT', () => { tnl.close(); process.exit(); });
修正后的完整代码示例
const MongoClient = require("mongodb").MongoClient; // 把require移到顶部,避免重复加载 const tunnel = require("tunnel-ssh"); // 别忘了引入tunnel-ssh哦 var config = { username: "root", password: "password on the server", // 注意原代码里是大写的Password,tunnel-ssh要求小写password host: "server IP address", port: 22, dstHost: "127.0.0.1", dstPort: 27017, localHost: "127.0.0.1", localPort: 27000 }; var tnl = tunnel(config, function(error, tunnelInstance) { if (error) { console.error("SSH隧道建立失败:", error); return; } console.log("SSH隧道已成功启动!"); getDataFromMongoDB(tunnelInstance); // 把隧道实例传入函数,方便关闭 }); async function getDataFromMongoDB(tunnel) { const uri = "mongodb://USRNAME:PASSWORD_FOR_MONGDB_DATABASE@localhost:27000"; // 修正端口 const client = new MongoClient(uri, { useNewUrlParser: true }); try { await client.connect(); console.log("MongoDB已成功连接"); const collection = client.db("my_database_name").collection("jobs"); const jobs = await collection.find().toArray(); console.log("获取到的jobs数据:", jobs); } catch (err) { console.error("操作出错:", err); } finally { // 确保资源被释放 await client.close(); tunnel.close(); console.log("资源已释放"); } } // 监听程序退出信号 process.on('SIGINT', () => { tnl.close(); process.exit(); });
内容的提问来源于stack exchange,提问作者bp123
相关产品推荐
相关产品推荐

