Express res.download чрезвычайно странное поведение

У меня есть серверная часть NodeJS, которая прослушивает запрос POST с пакетом json. Используя информацию из пакета json, он создает файл csv примерно из 15 000 строк, а затем использует res.download для отправки файла csv обратно клиенту.

Чтение из облачной базы данных в файл csv не проблема. Я проверил файл на сервере, все строки там, и они точны. Однако в файле, который загружается на стороне клиента, может быть обрезано несколько сотен строк. Похоже, что res.download () запускается слишком рано, хотя я явно установил, что поток завершается после завершения цикла for или он запускается, когда он должен, но файл csv все еще буферизуется или что-то в этом роде

Вот мой код:

Сторона сервера:

app.post('/dashboard/download_data', function (req, res) {
    let payload = req.body;
    ref.orderByKey().once("value", function (snapshot) {
        let data = snapshot.val();
        writer.pipe(fs.createWriteStream('C:\\user\\EVCS_portal\\out.csv'));
        for (let key in data) {
            if (data.hasOwnProperty(key)) {
                test_time = data[key]['time'];
                writer.write({
                    time: data[key]['time'],
                    ac2p: data[key]['ac2p'],
                    dcp: data[key]['dctp']
                })
            }
        }
        writer.end('This is the end of writing\n');
        writer.on('finish', () => {
            console.info(test_time);
            res.download('C:\\user\\EVCS_portal\\out.csv');
            console.info('file sent out!')
        });
    })

Клиентская сторона js:

firebase.auth().currentUser.getIdToken(true).then(function (idToken) {
        let xhr = new XMLHttpRequest();

        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4 && xhr.status === 200) {
                let a = document.createElement('a');
                a.href = window.URL.createObjectURL(xhr.response);
                a.download = download_date + '.csv';
                a.style.display = 'none';
                document.body.appendChild(a);
                a.click();
            }
        };

        let url = "/dashboard/download_data";
        xhr.open("POST", url, true);
        xhr.setRequestHeader("Content-Type", "application/json");
        xhr.responseType = 'blob';

        // Package our payload including the idToken and the date
        let data = JSON.stringify({"idToken": idToken, 'date': download_date});
        xhr.send(data);
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
236
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Код сервера кажется нормальным, но для кода клиента кажется, что загрузка слишком спешит.

Пожалуйста, посмотрите этот нить и попробуйте xhr.onload вместо xhr.onreadystatechange.

Спасибо за ваш ответ! Я пробовал это. Я просто заменил onreadystatechange на onload, и поведение не изменилось. Есть другие идеи?

jgv115 18.05.2018 07:31

Еще одна вещь, которая, как я полагаю, может вызвать проблему с volumn, - это createObjectURL, пожалуйста, посмотрите: stackoverflow.com/questions/28307789/…

Thomas Choy 18.05.2018 07:50
Ответ принят как подходящий

Вы не слушаете правильный поток для события 'finish', что приводит к отправке ответа до того, как csv закончит запись. Вы вызываете res.download(), когда writer завершил конвейерную передачу данных в поток, но не тогда, когда csv WriteableStream через fs.createReadStream() завершил запись всех передаваемых данных в своем потоке в файловую систему.

Вместо того, чтобы создавать WriteableStream для csv в pipe(), сохраните его в переменной и добавьте прослушиватель для события 'finish'. Прослушивание 'finish' на writer привело к тому, что ваш сервер ответил до того, как csv был готов.

app.post('/dashboard/download_data', function (req, res) {
  let payload = req.body;
  ref.orderByKey().once("value", function (snapshot) {
      let data = snapshot.val();

      let csvWriter = fs.createWriteStream('C:\\user\\EVCS_portal\\out.csv')

      writer.pipe(csvWriter);
      for (let key in data) {
          if (data.hasOwnProperty(key)) {
              test_time = data[key]['time'];
              writer.write({
                  time: data[key]['time'],
                  ac2p: data[key]['ac2p'],
                  dcp: data[key]['dctp']
              })
          }
      }
      writer.end('This is the end of writing\n');
      csvWriter.on('finish', () => {
          console.info(test_time);
          res.download('C:\\user\\EVCS_portal\\out.csv');
          console.info('file sent out!')
      });
  })
})

В этом есть смысл, теперь код работает отлично. Большое спасибо

jgv115 18.05.2018 08:17

Другие вопросы по теме