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

Node.js如何改写ssh2事件监听代码为async/await获取Promise结果

问题根源

外层作用域无法获取data的核心原因是:ssh2的连接建立、命令执行、流数据接收全是异步非阻塞逻辑,JS主线程不会阻塞等待这类异步操作执行完成,在外层编写console.log(data)逻辑时,数据流事件尚未触发,对应变量还未赋值,自然无法打印出内容。
将整个SSH执行流程封装进Promise、配合async/await语法,就可以用近似同步的写法获取异步返回的命令执行结果。

可直接使用的改写代码
const { readFileSync } = require('fs');
const { Client } = require('ssh2');

/**
 * 远程SSH执行命令封装
 * @param {object} sshConfig SSH连接配置
 * @param {string} command 要执行的shell命令
 * @returns {Promise<string>} 命令执行的STDOUT输出
 */
function execSSHCommand(sshConfig, command) {
  return new Promise((resolve, reject) => {
    const conn = new Client();
    let stdout = '';
    let stderr = '';

    conn.on('ready', () => {
      conn.exec(command, (err, stream) => {
        if (err) {
          conn.end();
          return reject(err);
        }

        stream.on('close', (code, signal) => {
          conn.end();
          if (code !== 0) {
            return reject(new Error(`命令执行退出码异常: ${code}, 信号: ${signal}, 错误输出: ${stderr}`));
          }
          // 正常退出返回标准输出
          resolve(stdout.trim());
        }).on('data', (data) => {
          // 拼接收集所有stdout数据块
          stdout += data.toString('utf8');
        }).stderr.on('data', (data) => {
          // 收集stderr输出
          stderr += data.toString('utf8');
        });
      });
    }).on('error', (err) => {
      // 捕获连接阶段错误
      reject(new Error(`SSH连接失败: ${err.message}`));
    }).connect(sshConfig);
  });
}

// 调用示例
async function runRemoteTask() {
  const sshConfig = {
    host: 'x.x.x.x',
    port: 22,
    username: 'abc',
    privateKey: readFileSync('./id_rsa')
  };
  const targetCommand = 'python ~/test.py';

  try {
    const output = await execSSHCommand(sshConfig, targetCommand);
    // 这里就能拿到完整的stdout输出,可在外层任意逻辑中使用
    console.log('远程脚本执行结果:', output);
    return output;
  } catch (err) {
    console.error('执行出错:', err.message);
    throw err;
  }
}

// 启动执行
runRemoteTask();
注意事项
  • 所有Promise返回的异步结果,必须在await关键字之后才能拿到,不要在await语句之前提前访问结果变量
  • 上述代码默认把输出转成utf8字符串,如果命令返回二进制内容(比如文件流),去掉toString('utf8')直接拼接Buffer即可
  • 连接失败、命令执行报错、脚本非0退出的异常都会被Promise抛出,必须用try/catch块捕获处理
  • 代码已经在流关闭、报错的所有分支主动调用了conn.end()断开连接,不会出现连接泄漏问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 14:15:53