Невозможно правильно передать данные узла в канал для загрузки файла - PullRequest
0 голосов
/ 04 мая 2018

Я довольно новичок в работе с узлами и потоковой передачей, и у меня возникла проблема при попытке передать большой объем данных в файл в клиентском браузере.

Так, например, если на сервере, если у меня есть большой файл test.txt, я могу легко передать его в браузер клиента, установив вложение заголовка и передав файл в ответ на запрос следующим образом.

res.setHeader('Content-Type', 'text/csv');
res.setHeader('Content-disposition', 'attachment;filename=myfile.text');

fs.createReadStream('./test.txt')
.pipe(res);

Когда пользователь нажимает кнопку, начинается загрузка, и мы видим, что данные передаются в файл загрузки. Поток занимает несколько минут, но в течение этого времени клиент не блокируется, и он может продолжать выполнять другие действия, пока файл загружается браузером.

Однако мои данные не хранятся в файле, мне нужно извлекать их по одной строке за раз с другого сервера. Итак, я пытаюсь создать свой собственный поток чтения и проталкивать свой фрагмент данных по фрагменту, но он не работает, когда я делаю что-то вроде этого:

var s = new Readable();
s.pipe(res);

for(let i=0; i<=total; i++) {
  dataString = //code here to get next string needed to push
  s.push(dataString);
};
s.push(null);

С помощью этого кода, когда пользователь запрашивает загрузку, после начала загрузки клиент блокируется и не может выполнять никаких других действий, пока загрузка не будет завершена. Кроме того, если для потоковой передачи данных требуется более 30 секунд, в этом случае истекает время ожидания сервера, и загрузка завершается неудачно. С файловым потоком это не проблема

Как мне заставить это действовать как файловый поток и не блокировать клиент от выполнения другого запроса во время загрузки. Буду признателен за любые рекомендации по наилучшему способу реализации этого.

1 Ответ

0 голосов
/ 04 мая 2018

Я смог решить эту проблему, выполнив что-то похожее на это: Как вызвать асинхронную функцию внутри читаемого потока node.js

Мой основной код выглядит следующим образом, и это не блокирует клиента и не приводит к истечению времени ожидания по запросу, поскольку данные непрерывно передаются в файл для загрузки на стороне клиента.

res.setHeader('Content-Type', 'text/csv');
res.setHeader('Content-disposition', 'attachment;filename=myfile.text');

function MyStream() {
  var rs = new Readable();
  var hitsadded = 0;

  rs._read = function() {}; // needed to avoid "Not implemented" exception

  getResults(queryString, function getMoreUntilDone(err, res) {
      if (err){
        logger.logError(err);
      }

      rs.push(res.data);
      hitsadded += res.records;

      if (res.recordsTotal > hitsadded) {
        getNextPage(query, getMoreUntilDone);
      } else {
        rs.push(null);
      }
    });
  return rs;
}

 MyStream().pipe(zlib.createGzip()).pipe(res);
...