Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 941
Pi Home Server Avatar asked Sep 07 '15 15:09

Pi Home Server


People also ask

How do I download a file from NodeJS server?

var path = require('path'); var mime = require('mime'); var fs = require('fs'); app. get('/download', function(req, res){ var file = __dirname + '/upload-folder/dramaticpenguin. MOV'; var filename = path. basename(file); var mimetype = mime.

Can I use AngularJS with NodeJS?

If you are writing an AngularJS front end web application, you may never have to use NodeJS. If you need tooling (build scripts to compile Sass, linters, etc) in your development or deployment process you can use NodeJS task runners like Gulp, Grunt or Webpack.

How can I download file in Angular?

Angular Download Link You'll use an anchor tag pointing to the file with the href attribute. The download attribute informs the browser that it shouldn't follow the link but rather download the URL target. You can also specify its value in order to set the name of the file being downloaded.


2 Answers

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')
  });
like image 153
Pi Home Server Avatar answered Sep 30 '22 13:09

Pi Home Server


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

like image 21
sdgluck Avatar answered Sep 30 '22 13:09

sdgluck