Node.js中使用ssh2-sftp-client下载SFTP全量文件及FTP实现咨询
SFTP 递归下载完整实现方案
现有代码问题
await data.forEach()写法无效,forEach 没有返回 Promise,无法等待所有下载任务完成,容易出现连接提前断开、文件下载不全的问题- 未判断远程条目类型,直接调用
sftp.get()遇到文件夹会直接报错 - 没有处理嵌套子目录,也没有提前创建本地对应层级的目录结构
修复后可递归下载所有文件/文件夹的代码
const fs = require('fs/promises') const Client = require('ssh2-sftp-client') const sftp = new Client() checkCtrl.checkSftp = async (req, res) => { const { url: host, username, password, port, remotePath = '/', localPath = './ftp' } = req.body // 递归下载函数封装 const downloadDir = async (remoteDir, localDir) => { // 递归创建本地目录,不存在自动生成父级目录 await fs.mkdir(localDir, { recursive: true }) // 获取远程目录下所有条目 const entries = await sftp.list(remoteDir) // 并行处理所有条目,等待全部任务完成 await Promise.all(entries.map(async entry => { const curRemotePath = `${remoteDir}/${entry.name}`.replace(/\/+/g, '/') const curLocalPath = `${localDir}/${entry.name}` // 类型为d代表目录,递归调用下载 if (entry.type === 'd') { await downloadDir(curRemotePath, curLocalPath) // 类型为-代表普通文件,直接下载 } else if (entry.type === '-') { const fileStream = await sftp.get(curRemotePath) await fs.writeFile(curLocalPath, fileStream) } })) } try { // 建立连接 await sftp.connect({ host, port, username, password, keepaliveInterval: 2000, keepaliveCountMax: 20 }) // 启动递归下载 await downloadDir(remotePath, localPath) // 下载完成关闭连接 await sftp.end() res.status(200).send('下载成功') } catch (err) { console.log('下载出错', err) await sftp.end().catch(() => {}) res.status(400).send('下载失败') } }
代码支持自定义远程下载路径和本地存储路径,自动处理多层嵌套目录,所有异步任务执行完成后才会返回响应。
FTP 服务器同款功能实现建议
- 推荐使用
basic-ftp包实现 FTP 连接操作,逻辑和 SFTP 实现完全一致- 建立 FTP 连接后调用
list()方法获取指定目录下的所有条目 - 同样通过条目类型判断是目录还是普通文件,目录递归处理,文件调用
downloadTo()方法直接下载到本地路径 - 下载前用
fs.mkdir({recursive: true})提前创建本地对应目录结构
- 建立 FTP 连接后调用
- 注意配置 FTP 连接的被动模式,大部分公网 FTP 服务器都要求使用被动模式连接
- 下载完成后手动调用
close()方法关闭 FTP 连接,避免连接资源泄漏
内容的提问来源于stack exchange,提问作者Erraco
相关产品推荐
相关产品推荐

