Reputation: 487
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
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
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