节点JS-在promise-ftp上没有管道就无法获取流数据

时间:2018-10-30 12:05:06

标签: node.js api express ftp

伙计们,当我尝试从FTP获取文件然后通过我的API以base64的形式发送文件时,遇到了Express上的Node.js api问题。

我正在使用-> 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'));时不起作用。

我不确定这里是什么管道。

你能帮我吗?

1 个答案:

答案 0 :(得分:1)

readable.pipe(writable)是Node的Stream API的一部分,该API透明地将从可读文件中读取的数据写入可写流,从而为您处理背压。将数据传输到文件系统是不必要的,并且Express Response对象实现了可写的流接口,因此您可以将通过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 / await的Node版本,那么这是一个Promise版本:

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()

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