You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js用ssh2-sftp-client定时上传报错:已有SFTP连接存在

问题:ssh2-sftp-client重复上传报错“An existing SFTP connection is already defined”

在Node.js应用中使用ssh2-sftp-client工具,每5秒执行一次图片上传操作。首次上传成功,但重复执行时触发错误:Error: connect: An existing SFTP connection is already defined。

原代码如下:

let Client = require('ssh2-sftp-client');
let sftp = new Client();


function uploadScreenshot() {
    randomNumber = Buffer.from(Math.random().toString()).toString("base64").substring(10,15);
    filename = "test_screenshot_upload"+randomNumber+".png";
    sftp.connect({
      host: 'ssh.strato.de',
      port: '22',
      username: 'user',
      password: 'pass'
  }).then(() => {
    sftp.put('screenshot.png', '/path/folder/folder/'+filename);
  }).then(data => {
      console.log("uploaded screenshot to server as " + filename);
  }).catch(err => {
    console.log(err, 'catch error');
  });  
}

function foo() {
    uploadScreenshot();
    setInterval(foo, 5000);
}

foo();

尝试在sftp.put后添加sftp.end()但未解决问题,需要排查原因及修复方案。


问题原因与修复方案

核心原因

  1. 重复调用connect():仅创建了一个全局sftp实例,第一次调用uploadScreenshot时已通过connect()建立连接,后续重复调用connect()会触发“已有连接存在”的报错。
  2. Promise链式调用错误:sftp.put()是异步Promise操作,原代码未返回该Promise,导致后续then在上传未完成时就执行;即便添加sftp.end(),也会因提前关闭连接导致上传失败或连接状态异常。
  3. 定时器逻辑错误:foo()内部调用setInterval(foo, 5000)会不断创建新定时器,最终上传频率会越来越高,引发更多连接问题。

修复方案

方案1:每次上传创建新实例(简单直观)

每次上传时创建新的SFTP客户端实例,上传完成(或出错)后关闭连接,避免重复使用同一实例:

let Client = require('ssh2-sftp-client');

function uploadScreenshot() {
    // 每次上传创建新的客户端实例
    const sftp = new Client();
    const randomNumber = Buffer.from(Math.random().toString()).toString("base64").substring(10,15);
    const filename = `test_screenshot_upload${randomNumber}.png`;
    
    sftp.connect({
      host: 'ssh.strato.de',
      port: 22,
      username: 'user',
      password: 'pass'
    })
    // 必须return put的Promise,保证链式调用顺序
    .then(() => sftp.put('screenshot.png', `/path/folder/folder/${filename}`))
    .then(() => {
        console.log(`uploaded screenshot to server as ${filename}`);
        // 上传完成后关闭连接
        return sftp.end();
    })
    .catch(err => {
        console.log(err, 'catch error');
        // 出错时也要关闭连接,避免资源泄漏
        sftp.end();
    });  
}

// 直接设置定时器调用上传函数,避免嵌套创建多个定时器
setInterval(uploadScreenshot, 5000);
// 首次立即执行上传
uploadScreenshot();

方案2:复用长连接(更高效)

只在首次上传时建立连接,后续复用该连接;若连接断开,自动尝试重连:

let Client = require('ssh2-sftp-client');
const sftp = new Client();
let isConnected = false;

// 封装连接逻辑,确保仅在未连接时建立连接
function connectSFTP() {
    if (isConnected) return Promise.resolve();
    
    return sftp.connect({
      host: 'ssh.strato.de',
      port: 22,
      username: 'user',
      password: 'pass'
    })
    .then(() => {
        isConnected = true;
        console.log('SFTP连接已建立');
    })
    .catch(err => {
        console.log('SFTP连接失败', err);
        isConnected = false;
        throw err;
    });
}

function uploadScreenshot() {
    const randomNumber = Buffer.from(Math.random().toString()).toString("base64").substring(10,15);
    const filename = `test_screenshot_upload${randomNumber}.png`;
    
    // 先确保连接正常,再执行上传
    connectSFTP()
    .then(() => sftp.put('screenshot.png', `/path/folder/folder/${filename}`))
    .then(() => {
        console.log(`uploaded screenshot to server as ${filename}`);
    })
    .catch(err => {
        console.log(err, 'catch error');
        // 连接出错时标记为未连接,下次尝试重连
        isConnected = false;
    });  
}

setInterval(uploadScreenshot, 5000);
uploadScreenshot();

内容的提问来源于stack exchange,提问作者Genesis1337

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 05:10:31