download .zip file from server in nodejs - angularjs

I am using MEAN, in which I want to allow user to download zip file from server.
So basically I have to do following things:
Create csv files from certain data.
Store that file into some directory.
Compress these file to zip.
When a user clicks on the button, zipped file should be downloaded and readable.
I have achieved 1,2,3 completely, and 4 partially. In this I have been able to successfully download zip file, but this file is in corrupted format and I am not able to read this file.
My code for download functionality is here:
html:
Download CSV Reports
angular part:
$scope.downloadFiles = function() {
$http({
method: 'GET',
url: '/download/csv/files'
}).
success(function(data, status, headers, config) {
var anchor = angular.element('<a/>');
anchor.attr({
href: 'data:attachment' + encodeURI(data),
target: '_blank',
download: 'filename.zip'
})[0].click();
}).
error(function(data, status, headers, config) {
alertify.error(data);
});
};
NodeJS:
var path = require('path'),
fs = require('fs');
exports.downaloadAllCsv = function(req, res) {
var file = 'local path to my zip file',
filename = path.basename(file);
res.setHeader('Content-disposition', 'attachment; filename=' + filename);
res.setHeader('Content-type:',' application/zip');
var filestream = fs.createReadStream(file);
filestream.pipe(res);
};

I used an npm library called express-zip (found here: https://www.npmjs.com/package/express-zip)
Using Node 4.X and Express 4.X, I can download a zip file from my browser. Getting it to work through Angular is what lead me to my own question:
Client download of a server generated zip file
Given all of that, here is my server code that worked:
Node (4.X) code with express-zip:
router.get('/bulkdownload',function(req,resp){
var titles = req.query.titles || [];
if ( titles.length > 0 ){
utils.getFileLocations(titles).
then(function(files){
let filename = '/tmp/zipfile.zip';
// .zip sets Content-Type and Content-disposition
resp.zip(files,filename);
},
_errorCb)
}
});
The utils.getFileLocations(titles) returns a promise where files is an array like this:
[{path: '/path/to/file/file.abc',name:'file.abc'},{...},{...},...]
My .zip file is not corrupted, and is readable.

Related

Corrupt zip file downloaded in angular

Angular client code:
$http.post('/zip', {
id: _id
})
.success(function (data, status, headers, config) {
var blob = new Blob([data], {type: "application/zip"});
var contentDisp = headers('content-disposition');
if (contentDisp && /^attachment/i.test(contentDisp)) {
var fileName = contentDisp.toLowerCase()
.split('filename=')[1]
.split(';')[0]
.replace(/"/g, '');
//The below command works but generates a corrupt zip file.
FileSaver.saveAs(blob, fileName);
}
})
.error(function () {
console.log("Could not download");
});
NodeJS Server Code:
app.route('/zip/')
.post(function(req, res) {
var output = fs.createWriteStream(join(outdir, outzipfile));
//Using s3zip to archive.
s3Zip
.archive({ s3: s3Client, bucket: bucket}, folder, s3_files)
.pipe(output);
output.on('close', function() {
//This sends back a zip file.
res.download(outPutDirectory + outputBcemFile);
});
output.on('error', function(err) {
console.log(err);
return res.status(500).json({error: "Internal Server Error"});
});
});
Although FileSaver.saveAs works and downloads the zip file, it seems to be corrupted. Is the type "application/zip" correct? I have also tried "octet/stream" and it downloads a corrupt zip file too. Any help would be highly invaluable! Thanks.
This is a bug mentioned in Git in below link :
https://github.com/eligrey/FileSaver.js/issues/156
To solve you need to add : responseType: 'arraybuffer' to your $http Request headers and it will work.

How to download excel files generated by node [Node][Angular]

I use the same way it's mentioned in [Node][Angular] How to download excel files generated by node
but still I don't get any popup to open or save. I could see the buffer in the Network window of Chrome.
Any help is appreciated.
On the client side you can use:
$http({method: 'GET', url: '/someUrl'}).
success(function(data, status, headers, config) {
let blob = new Blob([data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const fileName = `file.xlsx`;
let file = new File([blob], fileName);
let fileUrl = URL.createObjectURL(file);
})
.error(function(data, status, headers, config){
});
I used File because it allows you to pass filename. You could skip this part and pass Blob to URL.createObjectURL. It opens window with download. Assuming your server code is correct. But if you see buffer in Chrome than it sends something.
For server side I usually use express res.sendFile. It needs you to create a file so you gave to clean up.

MEAN js download file from system path

I want to implement feature in MEANJS project to download mp3 files from system path
Example: /usr/local/setup/file.mp3
I want to apply security checks for valid user and allow user to download mp3 files.
Is there any other way which can be used to download files with security?
We can use below node js function
var path = require('path');
var fs = require('fs');
app.get('/api/download-music', function(req, res){
var filename = "file.mp3";
var filePath = path.join("/usr/local/setup/", filename);
var stat = fs.statSync(filePath);
res.writeHead(200, {
'Content-Type': 'audio/mp3',
'Content-Length': stat.size,
"content-disposition":"attachment; filename="+filename
});
var readStream = fs.createReadStream(filePath);
readStream.on('data', function(data) {
var flushed = res.write(data);
// Pause the read stream when the write stream gets saturated
if(!flushed)
readStream.pause();
});
res.on('drain', function() {
// Resume the read stream when the write stream gets hungry
readStream.resume();
});
readStream.on('end', function() {
readStream
.pipe(res);
});
});
}
in above node js code we can apply security checks with session id.
on angular template we can use below html:
Download

can not upload the file with its extension and original path name using Multer and Node.js

I have one issue while uploading the file using Multer module from Node.js.I am explaining my code below.
server.js:
var multer = require('multer');
var upload = multer({ dest: './upload/' });
var cpUpload = upload.fields([{ name: 'images', maxCount: 1}]);
var app=express();
var server=http.createServer(app);
var admin=require('./route/route.js');
app.post('/uploadAll',cpUpload,function(req, res, next){
console.log('fiels',req);
})
supplierController.js:
var file=fileURL;
var curnum=(Math.random() * new Date().getTime()).toString(36).replace(/\./g, '');
var newPicpath=curnum+"_"+ file.name;
file.name=newPicpath;
console.log('file',file);
$scope.upload=Upload.upload({
url: '/uploadAll',
method:'POST',
data:{
images: file,
},
headers : {
'Content-Type': 'multipart/form-data'
},
}).success(function(data, status, headers, config) {
}).error(function(data, status) {
console.log('err file',data);
})
inside console message i am getting the below file data.
Blob
$ngfName:"vse123ertgf_1.jpg"
name:"vse123ertgf_1.jpg"
size:8607
type:"image/jpeg"
Here you can check my file name is containing one random number with it.When i am uploading the file the file is uploaded inside the given folder but taking another random number(i.e-75149c6770ea216b5ad8aafa7698539d) as its name and without extension(i.e-.jpg or png).Here also i am getting the error response inside error function in client side.I am using ng-file-upload to upload the file.Here i need the file should upload inside the required folder using its original name what its taking in client side.Please help me to resolve this issue.
Satya. The issue you are facing is very common. Please read the following post for some beautiful insight. I had the same issue and I resolved it using this post. For further issue please comment below, will help you out.

NodeJS/Express4 endpoint generating corrupt xlsx file

I am trying to create an endpoint using NodeJS/express 4 that generates and send to the user a xlsx file.
To create the xlsx file I am using the node-xlsx library.
var xlsx = require('node-xlsx');
var buffer = xlsx.build([{
name: pasta,
data: data
}]);
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader("Content-Disposition", "attachment; filename=" + pasta + ".xlsx");
res.write(buffer, 'binary');
return res.end();
And I am trying to download this file through an Angular app.
$http.post('https://endpoint/v1/' + folderName + '/reportExcel', {
responseType: 'arraybuffer'
})
.success(function(response) {
var blob = new Blob([response], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
});
var objectUrl = URL.createObjectURL(blob);
$window.open(objectUrl);
However, the file that is being downloaded is broken, so I can not open it.
Could it because you are using connect-livereload plugin? The plugin seems cause corrupted binary files being transferred. I've encountered the same, and solved it by adding 'ignore' when initiate connect-livereload plugin.
app.use(require('connect-livereload')({
ignore:['.xls', '.xlsx']
}));
See this post for detail: https://github.com/intesso/connect-livereload/issues/39
I posted an answer here: https://stackoverflow.com/a/41103999/1623249
Basically, you need to get the buffer from node-xlsx, convert it to base64 and then decode it in the client.

Resources