使用Node.js ssh2-sftp-client批量传多文件遇限问题求助
问题分析与解决方案
这个问题我太熟悉了——你现在的代码犯了一个常见的错误:重复对同一个SFTP客户端实例调用connect方法,这直接导致了监听器泄漏和上传失败。
为什么会出现警告和上传失败?
Node.js的EventEmitter默认最多允许10个同类型监听器,你循环12次调用sendFile,而每次sendFile里都会执行sftp.connect(config)。每次调用connect,都会给这个唯一的sftp实例添加新的ready、error、close监听器,当监听器数量超过10个时,Node就会抛出MaxListenersExceededWarning。
更关键的是,重复连接同一个客户端实例会导致连接状态混乱,后面的上传请求根本无法正常执行,所以超出10个的文件传不上去。
修复方案:一次连接,批量上传
正确的做法应该是先建立一次SFTP连接,再用这个已连接的实例执行所有上传操作,而不是每次上传都重新连接。下面是修改后的代码:
const Client = require('ssh2-sftp-client'); // 重构sendFile:不再处理连接逻辑,只负责单个文件的上传 const sendFile = (sftp, filename) => { console.log(filename); // 生成远程文件路径 const remoteFilename = filename.substr(filename.lastIndexOf('/') + 1); const remotePath = `/home/pi/RetroPie/roms/atari2600/${remoteFilename}`; return sftp.put(filename, remotePath); }; // 主上传流程:使用async/await让逻辑更清晰 const batchUpload = async (req, results) => { const sftp = new Client(); try { // 只建立一次连接 await sftp.connect(req.body); // 生成所有上传任务的Promise数组 const uploadPromises = results.romlist.slice(0, 12).map(item => sendFile(sftp, item.filename) ); // 等待所有文件上传完成 await Promise.all(uploadPromises); // 上传成功返回响应 res.send('{"message":"OK"}'); } catch (err) { console.log(err, '上传出错'); // 出错时返回错误状态码 res.status(500).send('{"message":"上传失败"}'); } finally { // 无论成功或失败,确保关闭SFTP连接 await sftp.end(); } }; // 触发批量上传(根据你的实际业务场景调整调用时机) batchUpload(req, results);
关键改动说明
- 单次连接:把
sftp.connect()移到主流程中,只执行一次,避免重复添加监听器 - 职责拆分:
sendFile只专注于上传逻辑,依赖已连接的客户端实例 - 错误处理:使用
try/catch/finally确保无论上传成功或失败,连接都会被关闭,避免资源泄漏 - 代码可读性:用
async/await替代链式then,逻辑更直观
额外提示
如果你的业务场景需要同时处理超大量文件(比如几百个),可以考虑:
- 限制并发上传数量(比如一次同时传5个),避免服务器压力过大
- 若确实需要多个连接,可以创建多个
Client实例,而不是修改监听器上限(虽然可以用sftp.setMaxListeners(0)取消限制,但不推荐,因为会隐藏潜在的内存泄漏问题)
内容的提问来源于stack exchange,提问作者user1864255
相关产品推荐
相关产品推荐

