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
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.
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.
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.
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')
});
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().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With