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

React+Node.js上传文件至SFTP服务器失败问题求助

解决SFTP文件上传问题的方案

问题根源拆解

  1. 直接传inputFile后端收空对象:前端未用FormData封装文件,axios默认以JSON格式发送,无法正确传递二进制文件数据。
  2. DataURL方式上传失败:ssh2-sftp-client的put方法不支持DataURL格式,且你当前代码中remoteFilePath设为目录/,但put要求指定具体文件名,同时DataURL包含的前缀(如data:image/png;base64,)未处理。

方案一:用FormData直接上传文件(推荐,体积更小)

前端代码修改

调整文件上传逻辑,用FormData封装文件和参数:

async function handleDockerInput(e) {
  const inputFile = e.target.files[0];

  try {
    const loginResponse = await authService.logIn(user);
    console.log('Login Response: ', loginResponse);

    if (inputFile) {
      const formData = new FormData();
      // 添加文件
      formData.append('file', inputFile);
      // 注意:生产环境别直接传SFTP配置,建议后端存配置,前端传配置ID避免泄密
      formData.append('connect', JSON.stringify(SFTPConfig));
      // 传远程目录(后续后端拼接文件名)
      formData.append('remoteDir', '/');

      const response = await dockerService.putObject(formData);
      console.log(response);
    } else {
      alert('请选择要上传的文件');
    }
  } catch (error) {
    console.error('登录失败: ', error);
  }
}

修改dockerService.putObject,axios会自动处理multipart/form-data的请求头:

async putObject(formData) {
  const response = await axios.post('/docker/upload', formData);
  return response;
}

后端代码修改

  1. 先安装文件解析中间件multer:
npm install multer
  1. 配置multer并改造upload函数:
import multer from 'multer';
// 用内存存储文件,避免存本地直接上传SFTP
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });

// 路由中需先通过multer解析文件,示例:
// router.post('/docker/upload', upload.single('file'), yourController.upload);

public async upload(req: Request, res: Response): Promise<void> {
  // 获取上传的文件Buffer和原文件名
  const fileBuffer = req.file?.buffer;
  const fileName = req.file?.originalname;
  if (!fileBuffer || !fileName) {
    res.status(400).send('未上传有效文件');
    return;
  }

  // 解析SFTP配置和远程目录
  const connectConfig = JSON.parse(req.body.connect);
  const remoteDir = req.body.remoteDir;
  // 拼接完整远程文件路径(目录+文件名)
  const remoteFilePath = `${remoteDir}${fileName}`;

  const sftp = new Client();
  const sftpConfig: SftpConfig = {
    host: connectConfig.host,
    port: connectConfig.port,
    username: connectConfig.username,
    password: connectConfig.password,
  };

  try {
    await sftp.connect(sftpConfig);
    // 先检查远程目录是否存在
    const dirExists = await sftp.exists(remoteDir);
    if (!dirExists) {
      res.status(400).send('远程目录不存在');
      return;
    }
    // 上传Buffer到SFTP
    await sftp.put(fileBuffer, remoteFilePath);
    console.log('文件上传成功');
    res.status(200).send('文件上传成功');
  } catch (error) {
    console.error('SFTP上传错误:', error);
    res.status(500).send('上传文件到SFTP失败');
  } finally {
    await sftp.end(); // 确保连接关闭
  }
}

方案二:修复DataURL上传方式(不推荐,文件体积增大30%)

前端补充修改

在请求体中添加文件名:

const body = JSON.stringify({
  connect: SFTPConfig,
  filepath: dataUrl,
  remoteFilePath: '/',
  fileName: inputFile.name // 新增原文件名
});

后端代码修改

解码DataURL为Buffer,并指定远程文件名:

public async upload(req: Request, res: Response): Promise<void> {
  const dataUrl = req.body.filepath;
  const remoteDir = req.body.remoteFilePath;
  const fileName = req.body.fileName;
  
  if (!dataUrl || !fileName) {
    res.status(400).send('缺少DataURL或文件名');
    return;
  }

  // 去除DataURL前缀,解码为Buffer
  const base64Data = dataUrl.replace(/^data:.+;base64,/, '');
  const fileBuffer = Buffer.from(base64Data, 'base64');
  const remoteFilePath = `${remoteDir}${fileName}`;

  const sftp = new Client();
  const { host, port, username, password } = req.body.connect;

  const sftpConfig: SftpConfig = {
    host: host,
    port: port,
    username: username,
    password: password,
  };

  try {
    await sftp.connect(sftpConfig);
    const dirExists = await sftp.exists(remoteDir);
    if (!dirExists) {
      res.status(400).send('远程目录不存在');
      return;
    }
    await sftp.put(fileBuffer, remoteFilePath);
    console.log('文件上传成功');
    res.status(200).send('文件上传成功');
  } catch (error) {
    console.error('SFTP上传错误:', error);
    res.status(500).send('上传文件到SFTP失败');
  } finally {
    await sftp.end();
  }
}

关键注意事项

  • 安全风险:绝对不要在前端传递SFTP账号密码,建议后端存储配置,前端仅传递配置ID。
  • 错误排查:后端要打印完整错误信息(如console.error(error)),不要只返回自定义提示,方便定位问题。
  • 路径要求:ssh2-sftp-client的put方法必须指定具体文件名,不能只传目录。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 15:24:55