首页 > 解决方案 > Node JS - 在promise-ftp上没有管道无法获取流数据

问题描述

大家好,当我尝试从 FTP 获取文件然后通过我的 API 作为 base64 发送时,我遇到了我的 Node.js api 与 Express 的问题。

我正在使用 -> promise-ftp ( https://www.npmjs.com/package/promise-ftp )。

这是端点的样子:

getData = (req, res, next) => {
  const ftp = new PromiseFtp();
  let data = [];
  ftp.connect({host: 'xxxl',user: 'xxx',password: 'xxx'})
  .then(() => {
      return ftp.get('xxx.pdf');
    }).then((stream) => {
      return new Promise((resolve, reject) => {
        stream.once('close', resolve);
        stream.once('error', reject);
        stream.pipe(fs.createReadStream('test.pdf'));
        
        stream
        .on('error', (err) => {
          return res.send({errorMessage: err});
        })
        .on('data', (chunk) => data.push(chunk))
        .on('end', () => {
          const buffer = Buffer.concat(data);
          label = buffer.toString('base64');
          
          return res.send(label);
         });
      });
    }).then(() => {
      return ftp.end();
    });
}

问题是我不想将此文件本地保存在 api 文件旁边,当我删除行时stream.pipe(fs.createReadStream('test.pdf'));它不起作用。

我不确定管道在这里做什么。

你能帮帮我吗?

标签: node.jsapiexpressftp

解决方案


readable.pipe(writable)是 Node 的 Stream API 的一部分,它透明地将读取的数据写入可写流,为您处理背压。无需将数据通过管道传输到文件系统,ExpressResponse对象实现了可写流接口,因此您可以将 FTP 承诺返回的流直接通过管道传输到res对象。

getData = async (req, res) => {
  const ftp = new PromiseFtp();
  try {
    await ftp.connect({host: 'xxxl',user: 'xxx',password: 'xxx'});
    const stream = await ftp.get('xxx.pdf');
    res.type('pdf');
    await new Promise((resolve, reject) => {
      res.on('finish', resolve);
      stream.once('error', reject);
      stream.pipe(res);
    });
  } catch(e) {
    console.error(e);
  } finally {
    await ftp.end();
  }
}

如果你没有支持async/的 Node 版本await,这里是 Promise-only 版本:

getData = (req, res) => {
  const ftp = new PromiseFtp();
  ftp
    .connect({host: 'xxxl',user: 'xxx',password: 'xxx'})
    .then(() => ftp.get('xxx.pdf'))
    .then(stream => {
      res.type('pdf');
      return new Promise((resolve, reject) => {
        res.on('finish', resolve);
        stream.once('error', reject);
        stream.pipe(res);
      });
    })
    .catch(e => {
      console.error(e);
    })
    .finally(() => ftp.end());
}

在这里,您有一个很好的使用 Promise 的finally()- 方法或try/catch/finally块的用例,这将确保ftp.end()即使发生错误也会被调用。

请注意,我故意省略了将错误发送回客户端,因为这样做可能会泄漏敏感信息。更好的解决方案是使用请求上下文设置适当的服务器端日志记录。


推荐阅读