使用 AngularJS 从 Node.JS 服务器下载文件

Download a file from Node.JS server with AngularJS

我想用我的浏览器从我的服务器 运行 NodeJS 下载文件。 在服务器端,提供我拥有的文件:

exports.download = function(req, res) {
  var filename = "33.jpg";
  var filePath = path.join(__dirname, '..', '..', 'downloads', filename);
  var stat = fs.statSync(filePath);

  var fileToSend = fs.readFileSync(filePath);

  res.writeHead(200, {
      'Content-Type': 'image/jpeg',
      'Content-Length': stat.size,
      'Content-Disposition': filename
  });
  res.end(fileToSend);
};

名为 33.jpg 的文件存在并且大小为 744Kb。客户来电效果很好

在客户端 AngularJS 下面是我如何调用 post 调用来获取文件(当前未使用参数 uri):

$scope.downloadTrack = function(uri) {
  $http.post('/api/files/download', {uri: uri}).then(function(response) {
    var blob = new Blob([response.data], { type: 'image/jpeg' });
    var fileName = response.headers('content-disposition');
    saveAs(blob, fileName);
  }, function(response) {
    console.log('Download error');
    console.log(response);
  });
}

headers没问题(我可以找回文件名)

我的问题是下载了一个文件,但大小为 1.5Mb,无法读取。我尝试了不同的流方法,将数据附加到响应、管道等,但没有成功。 另一点(不确定是否重要):在 Safari 中打开文件时显示损坏的图标,在 Chrome 中保存文件

PS : 如果信息有用,我用 Yeoman 创建了项目

谢谢大家

[更新] 新版服务器功能(还不能用)

exports.download = function(req, res) {
  var filename = "33.jpg";
  var filePath = path.join(__dirname, '..', '..', 'downloads', filename);
  var stat = fs.statSync(filePath);
  var fileToSend = fs.readFileSync(filePath);
  res.set('Content-Type', 'image/jpeg');
  res.set('Content-Length', stat.size);
  res.set('Content-Disposition', filename);
  res.send(fileToSend);
};

[更新 2] 双倍大小的文件在文件中随机包含额外的 "efbffd" 字符序列,使其无法读取

您使用 res#end 而不是 res#send(带有 S)来发送响应的头部而不是正文。

exports.download = function(req, res) {
    // ...
    res.send(fileToSend);
};

来自 Express documentation 对于 res#end:

Use to quickly end the response without any data. If you need to respond with data, instead use methods such as res.send() and res.json().

通过将响应类型定义设置为 blob

解决了问题
  $http({
      url: '/api/files/download',
      method: "POST",
      data: {
        uri: uri
      },
      responseType: 'blob'
  }).then(function (response) {
      var data = response.data;
      var headers = response.headers;
      var blob = new Blob([data], { type: 'audio/mpeg' });
      var fileName = headers('content-disposition');
      saveAs(blob, fileName);
  }).catch(function (response) {
    console.log('Unable to download the file')
  });