【问题标题】:Express res.download extremely weird behaviourExpress res.download 极其奇怪的行为
【发布时间】:2018-10-28 10:42:34
【问题描述】:

我有一个 NodeJS 后端,它使用 json 包侦听 POST 请求。它使用 json 包中的信息构建一个大约 15,000 行的 csv 文件,然后使用 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.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);

【问题讨论】:

    标签: javascript node.js


    【解决方案1】:

    服务端代码看起来还可以,但是客户端代码似乎下载太匆忙了。

    请查看thread 并尝试使用 xhr.onload 代替 xhr.onreadystatechange。

    【讨论】:

    • 感谢您的回复!我试过这个。我只是将 onreadystatechange 替换为 onload 并且行为仍然存在。还有其他想法吗?
    • 我猜可能会遇到卷问题的另一件事是 createObjectURL 请看一下:stackoverflow.com/questions/28307789/…
    【解决方案2】:

    您没有收听 'finish' 事件的正确流,这会导致您在 csv 完成写入之前发送响应。当writer 完成将数据传输到流中时,您正在调用res.download(),但这不是当通过fs.createReadStream() 的csv WriteableStream 完成将其流中的所有管道数据写入文件系统时。

    不要为pipe() 中的csv 创建WriteableStream,而是将其保存在一个变量中并为'finish' 事件添加一个侦听器。在 writer 上侦听 'finish' 会导致您的服务器在 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!')
          });
      })
    })
    

    【讨论】:

    • 这很有意义,代码现在可以完美运行。非常感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-03
    • 1970-01-01
    • 1970-01-01
    • 2017-12-12
    • 1970-01-01
    • 2013-01-17
    相关资源
    最近更新 更多