6

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

2
  • res.write(fileToSend);res.end(); Commented Sep 8, 2015 at 8:08
  • Same result. I guess the issue comes from the Angular method more than the Node.JS side ... Commented Sep 8, 2015 at 8:51

2 Answers 2

10

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')
  });
Sign up to request clarification or add additional context in comments.

2 Comments

Error: saveAs is not defined in my console. how to resolve
install module angular-file-saver and put SaveAs factory as a parameter to your controller
1

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().

1 Comment

Thanks. I corrected (also the set headers part) but the result is the same : a received file twice size than the original and unreadable by the browser (and os)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.