I have a service that builds a csv file, and returns it to the user. Currently using expressjs v4.14, nodejs v8.7.0. My problem is that I get a download failed due to 'network error' in chrome when I call the service for it to create a large csv file. With smaller files, the service works fine. I can also browse to the /temp/ folder, and the entire expected file exists. In each case of 'things i tried', I was able to download smaller files but not the large ones.
Service:
download.post('/csv', (req, res, next) => {
res.status(200).header('Content-Type', 'text/csv');
const newUUID = uuid.v1();
let ws: WriteStream = fs.createWriteStream(`${__dirname}/../../temp/${newUUID}.csv`);
ws.on('finish', () => {
res.download(`${__dirname}/../../temp/${newUUID}.csv`);
});
//csv file built here
ws.write('huge stuff easily 50k rows and 10 mb file');
ws.end();
});
Chrome Error:
Chrome's network tab and developer console do not give me any indication of what happened. This download popup is all I get. I cleared everything in cookies/cache just in case and it did not help.
Things I tried:
writing chunks directly to response stream.
using readable stream https://nodejs.org/api/stream.html#stream_readable_streams , converting String into bytes and piping it.
creating a file locally (writestream) and streaming it back (readstream pipe into res)
res.download(file) after writestream creating local file ended
Update:
Ended up trying the service from postman and it worked, so I think it is an angularjs issue.
Angularjs
$http({
cache: false,
url: "/download/csv",
headers: {
'accept': 'text/csv'
},
method: 'POST',
data: {
rows: rows,
title: title ? title : ''
}
}).success(function (data, status, headers, config) {
var anchor = angular.element('<a/>');
anchor.attr({
href: 'data:attachment/csv;charset=utf-8,' + encodeURI(data),
target: '_blank',
download: 'csv_info.csv'
})[0].click();
}).error(function (data, status, headers, config) {
});
Turned out to be a limitation from href attribute from the anchor tag created in angularjs. This was solved using FileSaver:
$http({
cache: false,
url: "/download/csv",
headers: {
'accept': 'text/csv'
},
method: 'POST',
data: {
rows: rows,
title: title ? title : ''
}
}).success(function (data, status, headers, config) {
var file = new File([data], "info.csv", {type: "text/csv;charset=utf-8"});
saveAs(file);
}).error(function (data, status, headers, config) {
});
Related
I have Installed elasticsearch-6.3.1 in windows & try to filter the data by using following code in angular 1,it gives CORS error
$http({
url: 'http://localhost:9200/empinfo/employeedetails/_search',
method: "POST",
data: "{ 'query': { 'query_string': { 'query': 'Sujit','fields':['name'] } } }",
headers: { 'Content-Type': 'application/json' }
}).success(function (data, status, headers, config) {
console.log(data);
}).error(function (data, status, headers, config) {
});
My Elastic search error in angular.js
Although I have added Allow CORS in elasticsearch.yml file.
Please help me.
You need to uncomment the lines in your yml file.
Simply remove '#' from the beginning of each line. Restart your Elasticsearch.
cookie does show in browser however cannot be accessed using $cookie.get('io'). What am I missing. I also tried $timeout with 5 seconds delay. I tried to see in headers() but this token does not show there.
Code:
$http({
url: 'http://localhost:8081/api/v1/login',
method: 'POST',
data: $httpParamSerializerJQLike({
username: username,
password: password,
REQUEST_TYPE: requestType
}), // Make sure to inject the service you choose to the controller
headers: {
'Content-Type': 'application/x-www-form-urlencoded' // Note the appropriate header
}
}).success(function (data, status, headers, config) {
//10 seconds delay
$timeout( function(){
var favoriteCookie = $cookies.get('io');
alert(favoriteCookie);
}, 5000 );
//time
var time = 0;
//timer callback
var timer = function() {
if( time < 5000 ) {
time += 1000;
$timeout(timer, 1000);
}
}
//run!!
$timeout(timer, 1000);
//console.log(response.headers('set-cookie'));
callback(response = { success: true });
}).error(function (data, status, headers, config) {
callback(response = { success: false });
});
Please check that the cookie you are trying to get is not tagged as httpOnly.
When you tag a cookie with the HttpOnly flag, it tells the browser
that this particular cookie should only be accessed by the server. Any
attempt to access the cookie from client script is strictly forbidden.
Of course, this presumes you have: A modern web browser. A browser
that actually implements HttpOnly correctly.
it was autogenerated cookie. the cookie which i was trying to access did not appear in the browser. I had to make some code modifications in angularjs to get the cookie into browser. I had to include a parameter "withCredentials:true," in the http request. As soon as I did it my cookie appeared in the browser. Now my http request look like this.
$http({
url: 'http:localhost/login',
method: 'POST',
data: $httpParamSerializerJQLike({
username: username,
password: password,
REQUEST_TYPE: requestType
}), // Make sure to inject the service you choose to the controller
withCredentials:true,
headers: {
'Content-Type': 'application/x-www-form-urlencoded;
}
}).success(function (data, status, headers, config) {
callback(response = { success: true });
}).error(function (data, status, headers, config) {
callback(response = { success: false });
});
}
here is the situation.
I have an angular app that need to be used via a machine on wich you can put an USB key.
Several exports are possible from the corresponding backend and thoses exports (pdf, csv or rtf) need to be downloaded directly on the key, without asking the user.
Furthermore I need to be able to detect if the key is not present and show an error.
I don't think that it is doable using only angular with chromium.
I was thinking of making a local nodejs server on each machine that could access the filesystem for that. It works when using postman with form-data, but I don't know how I can pass a file donwloaded in angular to the nodejs server as a formdata, I keep getting incorrect pdf files.
TLDR :
I need to be able to have a chain like this :
get file from backend in angular
post a request to local (nodejs) server with the downloaded file
receive the file in nodejs to save it on disk
I am open to other ideas if this one doesn't work, as long as I can download this file I am happy.
current nodejs code, that works when i post the file using postman :
router.post('/save', function(req, res, next) {
console.log('savexvbxc');
var fstream;
//test if USB key is available
fs.stat(basePath, function(err, stats) {
if (err) {
console.log('error, key not present');
res.send(412, 'FAILURE');
}
var filename = basePath + 'toti.pdf';
console.log('filename is ' + filename);
if (req.busboy) {
console.log('busboy loaded');
req.busboy.on('file', function(fieldName, fileStream, fileName, encoding, mimeType) {
console.log('Saving: ' + filename + ' ' + fileName);
fstream = fs.createWriteStream(filename);
fileStream.pipe(fstream);
fstream.on('close', function() {
console.log('successfully saved ' + filename);
res.status(200).send('SUCCESS');
});
fstream.on('error', function(error) {
console.log('failed saved ' + filename);
console.log(error);
res.send(500, 'FAILURE');
});
});
req.busboy.on('error', function(error) {
console.log('failed saved ' + filename);
console.log(error);
res.send(500, 'FAILURE');
});
return req.pipe(req.busboy);
} else {
console.log('error, busboy not loaded');
res.send(500, 'FAILURE');
}
});
});
current angular code that do not work:
var dlReq = {
method: 'GET',
url: '/fep/documents/TVFI_FEP_0015_SFS_Specifications_Fonctionnelles_Detaillees_V00.9.pdf',
headers: {
'Content-Type': 'application/pdf',
'Accept': 'http://localhost:4000/fep/documents/TVFI_FEP_0015_SFS_Specifications_Fonctionnelles_Detaillees_V00.9.pdf'
},
responseType: 'arraybuffer'
};
$http(dlReq).then(function(data, status, headers, config) {
console.log(resp);
var file = new Blob([(resp)], {type: 'application/pdf'});
var formdata = new FormData();
formdata.append('file', file);
var request = {
method: 'POST',
url: 'http://localhost:4080/save',
data: formdata,
headers: {
'Content-Type': undefined,
'Accept': '*/*'
}
};
// SEND THE FILES.
$http(request)
.success(function(d) {
console.log('ok', d);
})
.error(function() {
console.log('fail');
});
});
Thank you
In angular, I want to download a text file containing a csv of userdata. Usually I have a form with a post action, but I want the user to stay on the same page, but return the csv data without any page referesh. The following is my post command:
$http({
url: "api/getUserData",
method: "POST",
data:{user_id:app.user_id}
}).success(function(data, status, headers, config) {
// data gets returned here
}).error(function(data, status, headers, config) {
$scope.status = status;
});
My problem is, the "data" that comes back from the post is a csv file. how can I get the data to actually "download" to the user's computer instead of living in the javascript? Is this even possible?
Here is the link to solution. It uses HTML5 FileSaver API to save the file as BLOB
You can do this :
Create temporary anchor ,
encode, your data & name your file using download attribute,
and then, fire a click event on it.
finally, remove the inserted element .
$http({
url: "api/getUserData",
method: "POST",
data:{user_id:app.user_id}
}).success(function(data, status, headers, config) {
// data gets returned here
var anchor = angular.element('<a/>');
angular.element(document.body).append(anchor); // Attach to document
anchor.attr({
href: 'data:attachment/csv;charset=utf-8,' + encodeURI(data),
target: '_blank',
download: 'myFileName.csv'
})[0].click(); // fire a click event.
anchor.remove(); // Clean it now ...
}).error(function(data, status, headers, config) {
$scope.status = status;
});
I have a working script that when the file input changes, pick the files, sign their upload data in my django backend, and upload it from the frontend directly to my s3 bucket. It's working great. I'm using ng-file-upload to do it.
var doSignUrl = function(image, success, error){
$http({
url: scope.signUrl,
params: {
s3_object_name: image.name,
s3_object_type: image.type
},
method: 'get'
}).success(success).error(error);
};
var getUploadConfig = function(image, data){
return {
url: data.url,
method: 'POST',
fields : {
key: data.path,
AWSAccessKeyId: data.aws_access_key_id,
acl: data.acl,
policy: data.policy,
signature: data.signature,
"Content-Type": image.type != '' ? image.type : 'application/octet-stream',
filename: data.file_name
},
file: image,
};
};
var doUpload = function(image){
doSignUrl(image, function(signData){
Upload.upload(getUploadConfig(image, signData)).progress(function(e){
doProgress(image, parseInt(100.0 * e.loaded / e.total))
}).success(function(data, status, header, config){
doSuccess(image, signData.url+'/'+signData.path);
}).error(function(data, status, header, config){
doError(image);
});
}, function(data, status, header, config){
console.log(status);
console.log(data);
});
}
for each file the file picker selects i call doUpload(file)
But my real objective is to crop the image in frontend using canvas before to upload. The problem is that when you crop image using canvas, the result is a base64 encoded image, not a file. So my final question is: is it Possible to upload this base64 image directly to s3?
With a lot of research i found out that you can send a blob instead of a file unsing ngFileUpload to s3.
I used this library to convert my base64 to a blob, and then passed the generated blob instead of the file in the Upload.upload() file parameter.