Send data to a nodeJs server using Ajax and busboy - javascript

I'm having some trouble sending data via Ajax to upload a file, if I send the data from the form directly, it works with the following code:
var fs = require('fs');
var fstream;
var folder = 'public/images/tmp/';
var path;
var images = [];
req.pipe(req.busboy);
req.busboy.on('file', function (fieldname, file, filename) {
if(filename){
if (!fs.existsSync(folder)) {
fs.mkdirSync(folder,0744);
}
path = folder+ filename;
fstream = fs.createWriteStream(path);
file.pipe(fstream);
} else {
path= undefined;
}
images.push(path);
res.send(images);
});
And the files are sent to the temp folder in the server. But I need to return images to my javascript, so with that data I can perform other actions.
Now, the options I am thinking are:
1- Find some way to avoid "data.send()" to redirect my form to the result view
2- Send the data with Ajax using a code similar to:
$.ajax( {
url: '/media',
type: 'POST',
data: new FormData(document.getElementById('#myFormId')),
success: //do things,
error: //do other things
});
but it doesn't work, I don't know wich format I should send my data to the POST function so it can work with busboy or if there is another way to copy the files to the server.
Thanks.

Related

Unable to download the file from Node.js using the POST request

I found a few questions related to the same but the answer didn't work for me so posting the same here.
I have some XML content which has been created programmatically and displayed in Textarea. I need an option to export or download the same to the local system. So I am using the POST request to send these data to NODE.JS where I am creating my XML file and trying to download it. I know if I am using the GET it would work directly but with POST it's failing. Is there a way I can do this?
Here is the code I have:
Angularjs POST request:
I have a button when clicked I am passing all the XML data to my NODE.js function:
$scope.ExportXML = function(XMLContent){
var XMLContent = XMLContent;
$http({
url : "/ExportData",
method : "POST",
data : XMLContent
}).success(function(data, status, headers, config) {
console.log(data);
console.log("Data Exported");
window.location.assign(data);
$window.open(data);
}).error(function(error, status, headers, config) {
console.log('ERROR: could not download file');
console.log(error)
});
}
My Node.js function which would create the XML file with the data:
const fs = require('fs');
const path = require('path');
const reqPath = path.join(__dirname, '../');
exports.exportfile = function(req,res)
{
var ContentData = req.body;
var FileName = "XMLDATA.xml";
fs.appendFile(FileName, ContentData, function (err)
{
const FilePath = reqPath+FileName;
res.download(FilePath);
})
}
As you can see from the success function of the ANGULARJS I tried a couple of things but none worked. I tried sending back the path of the file using the callback(FilePath); and then I am trying to download the file using the $window.open(data); but I am getting the following error Not allowed to load local resource:.
Can someone please help me with this?
After a bit of searching I was able to do it. Rather than sending the DATA to NODE.JS using the POST, I tried creating the file within my AngularjS function and downloaded it from there itself. if in case anyone is looking for the solution here it is:
//Export the contents of XML to text file
$scope.ExportXML = function(XMLContent){
var filename = 'HelloWorld.xml'
var blob = new Blob([XMLContent], {type: "text/xml"});
if (window.navigator && window.navigator.msSaveOrOpenBlob)
{
window.navigator.msSaveOrOpenBlob(blob, filename);
}
else
{
var e = document.createEvent('MouseEvents'),
a = document.createElement('a');
a.download = filename;
a.href = window.URL.createObjectURL(blob);
a.dataset.downloadurl = ['text/json', a.download, a.href].join(':');
e.initEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
a.dispatchEvent(e);
}
}

Can I send a zip file that is imported using input type and get the same zip in python?

I wanted to get the zip file in Python. I tried the following.
receive :function (event) {
var zipFile = new JSZip()
var file = event.target.files[0];
zipFile.loadAsync(file).then(function(content) {
return content.files["test.pdf"].async('text');
}).then(function (txt) {
var user = session.uid;
rpc.query({
model: 'account.invoice',
method: 'create',
args: [user,txt],
}).then(function (e) {
location.reload();
});
});
},
this is work on the change event on change of the input file. Here I am able to get the text inside the XML and can send it to python. But What if I have multiple files in the zip. If I am able to send the zip directly and can use the zip operation in python that would be perfect.
Thanks,
Lot of help is appreciated

Upload images to a Node.JS server without using <form>

I have a node.js server, which uses express-fileupload to accept images. Now I'm working on the function to upload an image. But I don't want to use < form > since I prefer xhtml request for various reasons, but mainly because I don't want to redirect the user, after he uploads an image.
I have tried reading the picture as dataURI, sending it to the server, decoding it and writing it to a file, which didnt work and seemed to resource intensive and laborious.
//I used the dataString from the callback method and wrote it to a file using fs.writeFile
function dataURItoimage(dataString, callback){
const atob = require("atob");
dataString.replace("data:image/jpeg;base64,", "");
dataString.replace("data:image/png;base64,", "");
atob(dataString);
callback(null, dataString);
}
//User side code
avatarInput.addEventListener("change", (e) => {
const reader = new FileReader();
reader.readAsDataURL(avatarInput.files[0]);
reader.onload = () => {
avatar = reader.result;
tosend.avatar = reader.result;
}
}, false);
uploadButton.onclick = () => {
var request = new XMLHttpRequest();
request.open("POST", "/avatarUpload");
request.setRequestHeader("Content-Type", "application/json");
var tosend = {avatar: ""};
tosend.avatar = avatar;
request.send(JSON.stringify(tosend));
}
Is there a better way to upload an image, which the user can select, to a node.js server?
You can try this example. It worked for me. I hope it can help you.
Sending dataURL throw Ajax request:
const dataURL = snapshotCanvas.toDataURL('image/png');
$.ajax({
url: 'http://localhost:3000/upload-image',
dataType: 'json',
data: { data: dataURL },
type: 'POST',
success: function(data) {}
});
Receiving request:
router.post('/', (req, res) => {
const base64 = req.body.data.replace(/^data:image\/png;base64,/, "");
fs.writeFileSync(`uploads/images/newImage.jpg`, base64, {encoding: 'base64'});
}
So I did it this way:
var request = new XMLHttpRequest();
request.open("POST", "/test");
var fd = new FormData();
fd.append("file", avatarInput.files[0]);
request.send(fd);
I created a FormData Object, appended the image, which the user chose in an input called "avatarInput", and send the object to the server.
On server side I used express-fileupload to access the file:
app.post("/test", (req, res) => {
if(req.files){
//With the follwing command you can save the recieved image
req.files.file.mv("./file.png", (err) => {if(err)throw err});
}
res.end();
});

Download image from express route

I have an express server running with the following route:
exports.getUserFile = function (req, resp) {
let filePath = path.join(__dirname, 'storage', req.params.fileName);
resp.download(filePath);
});
}
In my web app i'm calling this route and trying to save the file locally using file-saver:
let req = request.get('/users/' + userId + '/files/' + file.name);
req.set('Authorization', 'Bearer ' + this.state.jsonWebToken);
req.end((err, resp) => {
let f = new File([resp.text], file.name, {type: resp.type});
fileSaver.saveAs(f);
});
If the file is plain text then it works ok, but for other file types like images i'm not able to open the file (it's 'corrupt').
This is what the response looks like:
Do I need to decode the data in some way first? What is the correct way to save the content of the file?
If you're using superagent to perform the requests, you can explicitly set the response type to "blob", which would prevent any attempts to decode the response data. The binary data will end up in resp.body:
req.responseType('blob').end((err, resp) => {
saveAs(resp.body, file.name);
});
I haven't used express for a long time ago and I'm typing from mobile, it's seems a encoding issue, so it's seems that you're a sending raw image, you will need to encode it in base64 try something like:
//Here your saved file needs to be encoded to base 64.
var img = new Buffer(data, 'base64');
res.writeHead(200, {
'Content-Type': 'image/png',
'Content-Length': img.length
});
res.end(img);
Where data is your saved image, If you can render the image you just add the headers for download or just chain method download.
If you want to download the image as attachment in the page you can use res
exports.getUserFile = function (req, resp) {
let filePath = path.join(__dirname, 'storage', req.params.fileName);
var check = fs.readFileSync(__dirname+req.params.fileName);
resp.attachment(req.params.fileName); // The name of the file to be saved as. Eg Picture.jpg
res.resp(check) // Image buffer read from the path.
});
}
Reference:
http://expressjs.com/en/api.html#res.attachment
http://expressjs.com/en/api.html#res.end
Hope this helps.

Corrupt files when uploading from Node

I'm converting powerpoint files to individual images, and the images that are produced end up corrupted when I upload from Node.
The npm modules I'm using are request and node-form-data.
I upload a file from my Node app like this:
var request = require('request');
var FormData = require('form-data');
function processPresentation(fileName,fileLoc,userId,customerId){
var data = new FormData();
data.append('my_file',fs.createReadStream(fileLoc));
var options = {
url: config.getConverter()+"?tenant="+customerId+"&author="+userId+"&name="+fileName+"&ext=ppt",
method: 'POST',
form:data,
headers:{'x-auth-token':token,'Content-Type':'application/vnd.openxmlformats-officedocument.presentationml.presentation'}
};
request.post(options,function(error,response,body){
console.log(body);
if(error){
console.log('error',error);
}
if(!response){
}
if(response.statusCode === 200){
addPresentation(JSON.parse(body),userId);
}
});
}
And it goes through my conversion process, I get a file like this as output:
Here's what all this actually says, if you open the powerpoint file and look at the text:
http://pastebin.com/Dbh0JPKA
When I use Postman and upload the same file like this:
POST HTTP/1.1
Host: xxxx.xxxxxxxxxx.net?name=00a94ec9-8f70-4279-8972-f49935cda295&ext=ppt&tenant=543840f80019abda4937a9e2&author=543bef549f8d54a53a02f6d9
Content-Type: application/vnd.openxmlformats-officedocument.presentationml.presentation
x-auth-token: 772a5c0c023a447f68a9ac4fb2bb4bd39bafeb16b753df2222ffc835750cbbe6a4ef9ee82fab0902f39bc26851016a873d44c91a64f67de5e10044ef0787cebe
Cache-Control: no-cache
Postman-Token: 74aff430-f6b8-c7cd-d477-b9cc35897bb7
undefined
I get output like this:
Which is what I want.
Ok, I think that the problem is that you are sending mime/multipart encoded data and you just want to send the file as the raw body of the post. There are a couple ways to do this.
Option #1, Stream the File:
var options = {
url: config.getConverter()+"?tenant="+customerId+"&author="+userId+"&name="+fileName+"&ext=ppt",
headers:{'x-auth-token':token,'Content-Type':'application/vnd.openxmlformats-officedocument.presentationml.presentation'}
};
fs.createReadStream(fileLoc).pipe(request.post(options));
This technique is actually streaming the file as the raw post body for your request.
Option #2, Read the File then Post:
var options = {
url: config.getConverter()+"?tenant="+customerId+"&author="+userId+"&name="+fileName+"&ext=ppt",
headers:{'x-auth-token':token,'Content-Type':'application/vnd.openxmlformats-officedocument.presentationml.presentation'},
body: fs.readFileSync(fileLoc)
};
request.post(options, callback);
Here you are reading the file into a string and posting it using the body option. This sets the post body raw rather than using a mime/multipart encoding as you get with formData.
Try dropping the require for form-data and just do this:
var options = {
url: config.getConverter()+"?tenant="+customerId+"&author="+userId+"&name="+fileName+"&ext=ppt",
method: 'POST',
formData: {
my_file: fs.createReadStream(fileLoc)
},
headers:{'x-auth-token':token,'Content-Type':'application/vnd.openxmlformats-officedocument.presentationml.presentation'}
};
Important there is formData vs form
Doing this fixed it:
var length = fs.statSync(fileLoc).size;
console.log('length is',length);
var req = request.post({uri: config.getConverter()+"?tenant="+customerId+"&author="+userId+"&name="+fileName+"&ext=ppt",
headers:{
'x-auth-token':token,
'Content-Type':'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'content-length':length
}
});
fs.createReadStream(fileLoc).pipe(req).pipe(process.stdout);

Categories