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

6
我想使用浏览器从运行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);
  });
}

头部信息没问题(我能够检索到文件名)。
我的问题是下载的文件大小只有1.5MB,而且无法读取。我尝试了不同的方法,如使用流、将数据附加到响应中、管道等等,但都没有成功。 另一个问题(不确定是否重要):在Safari中,该文件打开时会显示损坏的图标,在Chrome中则会保存文件。
注:如果有用的话,我是使用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.write(fileToSend);res.end(); - AdityaParab
相同的结果。我猜问题来自于Angular方法而不是Node.JS端... - Pi Home Server
2个回答

10

通过将响应类型定义为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')
  });

错误:我的控制台中未定义saveAs。如何解决? - Satyam S
1
安装模块angular-file-saver,并将SaveAs工厂作为参数放入您的控制器中。 - Pi Home Server

1
使用res#end而不是res#send(带有S)发送响应头而不是响应体。
exports.download = function(req, res) {
    // ...
    res.send(fileToSend);
};

Express文档中了解到res#end:

用于快速结束响应,不返回任何数据。 如果需要返回数据,请使用res.send()和res.json()等方法。


谢谢。我已经进行了更正(包括设置头部),但结果仍然是一份比原始文件大两倍且无法被浏览器(和操作系统)读取的接收文件。 - Pi Home Server

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接