Pi Home Server
Pi Home Server

Reputation: 487

Download a file from Node.JS server with AngularJS

I would like to download files with my browser from my server running with NodeJS. On the server side, to serve the file i have :

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);
};

The file called 33.jpg exists and is 744Kb sized. The call from the client works great

On the client side with AngularJS here is how i call a post call to get the file (currently the parameter uri is not used) :

$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);
  });
}

The headers are ok (i can retrieve the file name)

My issue is that a file is downloaded but with a size of 1.5Mb and is unreadable. I tried different methods with streams, append data to response, pipe, etc. without success. Another point (not sure is important) : within Safari the files is opened with a broken icon displayed, within Chrome the file is saved

PS : i created the project with Yeoman if the information is useful

Thanks all

[Update] New version of server function (still not working)

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);
};

[Update 2] The double sized file contains extra "efbffd" char sequence randomly in the file making it unreadable

Upvotes: 6

Views: 10877

Answers (2)

Pi Home Server
Pi Home Server

Reputation: 487

Problem solved with a definition of the response type set to 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')
  });

Upvotes: 10

sdgluck
sdgluck

Reputation: 27217

You are sending the head of the response but not the body by using res#end instead of res#send (with an S).

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

From the Express documentation for 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().

Upvotes: 1

Related Questions