表达res.download非常奇怪的行为

时间:2018-05-18 04:17:20

标签: javascript node.js

我有一个NodeJS后端,用于侦听带有json包的POST请求。使用json包中的信息,它构建一个大约15,000行的csv文件,然后使用res.download将csv文件发送回客户端。

从云数据库读取到csv文件没问题。我检查了服务器中的文件,所有行都在那里,它们是准确的。但是,在客户端下载的文件可能会被切断几百行。似乎res.download()运行得太快,即使我已经明确地将流设置为一旦for循环结束或它正在运行时它应该但csv文件仍在缓冲或某事< / p>

这是我的代码:

服务器端:

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.log(test_time);
            res.download('C:\\user\\EVCS_portal\\out.csv');
            console.log('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);

2 个答案:

答案 0 :(得分:1)

您没有收听'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.log(test_time);
          res.download('C:\\user\\EVCS_portal\\out.csv');
          console.log('file sent out!')
      });
  })
})

答案 1 :(得分:-1)

服务器代码似乎没问题,但对于客户端代码来说似乎是让下载太快了。

请求查看此https://www.groupon.com/signup?metric=layout_login&return_to=https://www.groupon.com并尝试使用xhr.onload而不是xhr.onreadystatechange。