从Node.js通过Restify发送到客户端时,XLSX文件已损坏

时间:2015-11-20 18:23:18

标签: node.js excel xlsx restify filesaver.js

我正在开发一个项目,我正在使用XLSX node.js库创建一个excel文件,通过Restify将其发送到客户端,然后我使用FileSaver.js库将其保存在本地计算机上。当我将xlsx工作簿写入后端文件时,它打开正常,但是,当我在客户端打开它时,它已损坏。我收到错误:" Excel无法打开此文件。文件格式或文件扩展名无效。验证文件是否已损坏,文件扩展名是否与文件格式相符"。

以下是我在后端编写和发送文件的代码:

 var wopts = { bookType:'xlsx', bookSST:false, type:'binary' };
 var workbook = xlsx.write(wb, wopts);
 res.send(200, workbook);

在前端,我使用的是XLSX文档中的代码:

function s2ab(s) {
    var buf = new ArrayBuffer(s.length);
    var view = new Uint8Array(buf);
    for (var i=0; i!=s.length; ++i) 
        view[i] = s.charCodeAt(i) & 0xFF;
    return buf;
}

saveAs(new Blob([s2ab(response.data)],{type:""}), "test.xlsx");

有关为什么这不起作用的任何想法?任何帮助将非常感激。感谢。

1 个答案:

答案 0 :(得分:3)

正如Luke在评论中提到的,你必须在发送缓冲区之前进行base64编码。以下是使用NPM模块node-xlsx的代码段。

var xlsx = require('node-xlsx');

router.get('/history', function (req, res) {
  var user = new User();
  user.getHistory(req.user.userId, req.query.offset, req.query.limit)
    .then(function (history) {
      if (req.headers.contenttype && req.headers.contenttype.indexOf('excel') > -1) {
        var data = [['Data', 'amount'], ['19/12/2016', '10']];
        var xlsxBuffer = xlsx.build([{ name: 'History', data: data }]);
        res.end(xlsxBuffer.toString('base64'));
      } else {
        res.send(history);
      }
    })
    .catch(function (err) {
      res.status(500).send(err);
    });
});

这是使用Angular的前端代码:

  $scope.getXlsFile = function() {
    var config = {
      params: {
        offset: $scope.offset,
        limit: $scope.limit
      },
      headers: {
        'contentType': 'application/vnd.ms-excel',
        'responseType': 'arraybuffer'
      }
    };
    $http.get('/api/history', config)
      .then(function(res) {
        var blob = new Blob([convert.base64ToArrayBuffer(res.data)]);
        FileSaver.saveAs(blob, 'historial.xlsx');
      })
  }

其中convert是以下工厂:

.factory('convert', function () {
  return {
    base64ToArrayBuffer: function (base64) {
      var binary_string = window.atob(base64);
      var len = binary_string.length;
      var bytes = new Uint8Array(len);
      for (var i = 0; i < len; i++) {
        bytes[i] = binary_string.charCodeAt(i);
      }
      return bytes.buffer;
    }
  }
})