Can anyone tell me How to upload files Using nodejs and HAPI?
I am getting binary data inside the handler.
Here is my html code:
function sendFormFromHTML(form) {
//form = $(".uploadForm").form;
var formData = new FormData(form);
formData.append('id', '123456'); // alternative to hidden fields
var xhr = new XMLHttpRequest();
xhr.open('POST', form.action, true);
xhr.onload = function(e) { alert(this.responseText) };
xhr.send(formData);
return false;
}
<form method="post" id="uploadForm" action="http://localhost:3000/api/uploadfiles" enctype="multipart/form-data">
<label for="upload">File (Binary):</label>
<input type="file" name="upload" class="fileupload" /><br/>
<input type="button" class="submit" value="Submit" onclick="sendFormFromHTML(this.form);"/>
</form>
Here is My Nodejs code:
server.route({
method: 'POST',
path: '/api/uploadfiles',
config: {
handler: currentposition.uploadFiles,
}
});
uploadFiles:function(req,reply){
console.log(req.payload);
}
For new readers, hapi already using multiparty uses pez to handle multipart post requests. From hapi documentation;
If the payload is 'multipart/form-data' and parse is true, fields values are presented as text while files are provided as streams. File streams from a 'multipart/form-data' upload will also have a property hapi containing filename and headers properties.
Example;
server.route({
method: 'POST',
path: '/create',
config: {
payload:{
maxBytes: 209715200,
output:'stream',
parse: true
},
handler: function (request, reply) {
request.payload["htmlInputName"].pipe(fs.createWriteStream("test"));
}
});
You can visit for working code in https://github.com/pandeysoni/Hapi-file-upload-download
/*
* upload file
*/
exports.uploadFile = {
payload: {
maxBytes: 209715200,
output: 'stream',
parse: false
},
handler: function(requset, reply) {
var form = new multiparty.Form();
form.parse(requset.payload, function(err, fields, files) {
if (err) return reply(err);
else upload(files, reply);
});
}
};
/*
* upload file function
*/
var upload = function(files, reply) {
fs.readFile(files.file[0].path, function(err, data) {
checkFileExist();
fs.writeFile(Config.MixInsideFolder + files.file[0].originalFilename, data, function(err) {
if (err) return reply(err);
else return reply('File uploaded to: ' + Config.MixInsideFolder + files.file[0].originalFilename);
});
});
};
Finally I got the solution to upload the large files using HAPI and Thanks to Roman.
Here is the solution:
server.js code
server.route({
method: 'POST',
path: '/api/uploadfiles',
config: {
payload:{
maxBytes:209715200,
output:'stream',
parse: false
},
handler: currentposition.uploadFiles,
}
});
Handler code:
var currentpositionApi = {
fs : require('fs'),
multiparty: require('multiparty'),
uploadFiles:function(req,reply){
var form = new currentpositionApi.multiparty.Form();
form.parse(req.payload, function(err, fields, files) {
currentpositionApi.fs.readFile(files.upload[0].path,function(err,data){
var newpath = __dirname + "/"+files.upload[0].originalFilename;
currentpositionApi.fs.writeFile(newpath,data,function(err){
if(err) console.log(err);
else console.log(files)
})
})
console.log(files)
});
}
}
Related
I'm struggling uploading an image to a local folder using Node and Multer.
The response i get it's successfully, but the image don't save in the folder.
I have already lost a week trying to fix it
And yes, i have checked the destination route, in case you wonder.
This is my frontend:
<form id="tasasImage" enctype="multipart/form-data" style="display: flex; flex-direction: column;">
<input type="file" name="photo" id="photo" class="file"> <br>
<div id="uploadImg" class="btn btn-primary">ENVIAR</div>
</form>
<script>
$("#uploadImg").click(function () {
if ($('#photo').val().length > 0) {
var formData = new FormData($('#tasasImage')[0]);
console.log([...formData])
$.ajax({
url: "",
data: formData,
type: "POST",
processData: false,
contentType: false,
success: function(r){
console.log('Uploaded successfully');
$("#photo").val('');
},
error: function (e) {
console.log("some error", e);
}
});
}
</script>
And the backend:
var storageTasas = multer.diskStorage({
destination: function(req, file, callback) {
callback(null, config.urlBase+'public/images/tasas');
},
filename: function(req, file, callback) {
var name = now+'-'+file.originalname;
callback(null, name);
}
})
var uploadTasas = multer({ storage: storageTasas }).single('photo');
const tasasUploadImage = (req, res) => {
uploadTasas(req, res, (err) => {
if (err) { console.error(err); }
else {console.log('Ssuccessfully Uploaded') };
})
res.send({'file': now});
}
router.post('/admin/aliados/tasas/:id', adminController.tasasUploadImage);
The url you are passing empty in the JQuery / Client script, it should be url : /admin/aliados/tasas/1234
The form data should be like this
var formData = new FormData($('#tasasImage'));
simple multipart file upload with express.js and multer with ajax
I am trying to parse excel file data in the server and it is working fine but the problem is that it is saving file which we upload in the local disk in upload folder and then it is reading data.Here is the code which is working fine but when uploading large xlsx file is the issue because it will require extra memory and create same as another file in local disk.
server.route({
method: 'post',
path: `${(options.apiBase || '/xlsx/')}get`,
config: {
payload: {
output: 'stream',
parse: true,
allow: 'multipart/form-data'
}
},
handler: function (req, reply) {
try {
const data = req.payload;
if (data.file) {
let name = data.file.hapi.filename;
console.log("FIlename: " + name);
let path = __dirname + "/uploads/" + name;
let file = fs.createWriteStream(path);
data.file.pipe(file);
data.file.on('end', function (err) {
if (typeof require !== 'undefined')
XLSX = require('xlsx');
const workbook = XLSX.readFile(path);
console.log("row======>>>>");
const sheet_name_list = workbook.SheetNames;
const content =
XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list[0]]);
console.log(content);
var ret = {
filename: data.file.hapi.filename,
headers: data.file.hapi.headers
}
reply(JSON.stringify(content));
})
} catch (err) {
console.log('Err----------------------' + err);
// error handling
reply(Boom.badRequest(err.message, err));
}
}
});
next();
You need to set config.payload.parse to false. This will return the raw stream. But realize that if you're uploading multipart/form-data, you will need to parse it yourself.
config: {
payload: {
output: 'stream',
parse: false,
allow: 'multipart/form-data'
}
}
This is handled by the subtext module. See https://github.com/hapijs/subtext/blob/0bf83af78e364518577913db1bbc9c27bc739d7a/lib/index.js#L67
I am trying to parse Excel file data in server using hapi.js. I am getting file but data is in binary stream.
This is the code I am using and it need to parse file data to JSON from binary stream. So, XLSX file is coming to server side API as a binary stream. Now I need to read that binary stream and create file back and save locally at server API
server.route({
method: 'POST',
path: `${path..'/xlsx/')}get`,
config: {
handler: function (request, reply) {
const payload = request.payload
console.log(payload);
reply ('done');
},
payload: {
output: 'stream',
parse: true,
allow: 'multipart/form-data'
},
if (data.file) {
var name = data.file.filename;
var path = dirname + "/uploads/" + name;
var file = fs.createWriteStream(path);
console.log(path);
file.on('error', function (err) {
console.error(err)
});
data.file.pipe(file);
data.file.on('end', function (err) {
var ret = {
filename: data.file.filename,
headers: data.file.headers
}
reply(JSON.stringify(ret));
});
next();
I have a really quick question:
I have an img tag (in my template file) that holds an image and in my Angular Controller I call:
var image = document.getElementById('srcImage');
I want to send this image ^ to the backend (I am using REST). The url I would use for this POST method is:
'/api/v1/images/addImage'
I've tried ng-file-upload and $http.post, but nothing seems to be working. Is there any way that I can simply send this image over to the server so I can store it in a database or file system? I am open to any solutions to making this happen.
Thanks!!
You can use below libraries, they have good documentation also
For Frontend -
https://github.com/nervgh/angular-file-upload
For Backend -
https://github.com/expressjs/multer
Sample Snippet -
In HTML :
<input type="file" nv-file-select="" uploader="ctrl.uploader" multiple />
Angular Controller :
vm.uploader = new FileUploader({
url: 'http://' + SERVER_URL + '/upload',
formData: [{
id: 1
}]
});
vm.save = function() {
vm.uploader.onBeforeUploadItem = function (item) {
console.log(item);
/* some action */
};
vm.uploader.onSuccessItem = function (item, imgResponse, status, headers) {
console.log(item);
console.log(imgResponse);
console.log(status);
console.log(headers);
/* some action */
};
};
Node Server :
var fs = require('fs');
var multer = require('multer');
var fileName = '';
var storage = multer.diskStorage({
destination: function (req, file, cb) {
var dirPath = 'path/to/save/file'
if (!fs.existsSync(dirPath)) {
var dir = fs.mkdirSync(dirPath);
}
cb(null, dirPath + '/');
},
filename: function (req, file, cb) {
var ext = file.originalname.substring(file.originalname.lastIndexOf("."));
fileName = Date.now() + ext;
cb(null, fileName);
}
});
// Assuming Express -
app.get('/upload', function (req, res) {
var upload = multer({
storage: storage
}).array('file', 12);
upload(req, res, function (err) {
if (err) {
// An error occurred when uploading
res.json(err);
}
res.json(fileName);
});
});
You can try multipart/form-data like this:
<form id = "uploadForm"
enctype = "multipart/form-data"
action = "/api/photo"
method = "post"
>
<input type="file" name="userPhoto" />
<input type="submit" value="Upload Image" name="submit">
</form>
I created a node.js server that uses busboy to take requests, and pipe the files to Imgur for upload. However, I keep getting an "Uploading file too fast!" response from Imgur, and I'm not sure exactly what the problem is. Here is the code snippet involving busboy:
var express = require('express');
var Busboy = require('busboy');
var fs = require('fs');
var request = require('request-promise');
var router = express.Router();
router.post('/u', function(req, res, next) {
var busboy = new Busboy({headers: req.headers});
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
if(fieldname == 'image') {
var options = {
uri: 'https://api.imgur.com/3/image',
method: 'POST',
headers: {
'Authorization': 'Client-ID ' + clientID // put client id here
},
form: {
image: file,
type: 'file'
}
};
request(options)
.then(function(parsedBody) {
console.log(parsedBody);
})
.catch(function(err) {
console.log(err);
});
}
});
busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated) {
console.log('field');
});
busboy.on('finish', function() {
res.status(200).end();
});
req.pipe(busboy);
});
As you can see I'm piping the request file directly into my request for imgur. Providing a ReadStream by simply saving the file to disc and then using fs.createReadStream() works perfectly, so I'm not really sure why trying to pipe directly from request to request gives me the error. The exact response I'm getting from Imgur is:
StatusCodeError: 400 - {"data":{"error":"Uploading file too fast!","request":"\/3\/image","method":"POST"},"success":false,"status":400}
If anyone has encountered this before, it would be helpful...
The first issue is that you should be using formData instead of form for file uploads. Otherwise, the request library won't send the correct HTTP request.
The second issue is that the stream object won't have the correct content length until it's fully processed. We can buffer the data ourselves and pass it after the initial file stream from busboy has processed.*
This gives us something that looks like
var express = require('express');
var Busboy = require('busboy');
var fs = require('fs');
var request = require('request-promise');
var router = express.Router();
router.post('/u', function(req, res, next) {
var busboy = new Busboy({headers: req.headers});
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
if(fieldname == 'image') {
// the buffer
file.fileRead = [];
file.on('data', function(data) {
// add to the buffer as data comes in
this.fileRead.push(data);
});
file.on('end', function() {
// create a new stream with our buffered data
var finalBuffer = Buffer.concat(this.fileRead);
var options = {
uri: 'https://api.imgur.com/3/image',
method: 'POST',
headers: {
'Authorization': 'Client-ID ' + clientID // put client id here
},
formData: {
image: finalBuffer,
type: 'file'
}
};
request(options)
.then(function(parsedBody) {
console.log(parsedBody);
})
.catch(function(err) {
console.log(err);
});
});
}
});
busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated) {
console.log('field');
});
busboy.on('finish', function() {
res.status(200).end();
});
req.pipe(busboy);
});
Code for the buffering is from http://thau.me/2014/02/nodejs-streaming-files-to-amazons3/
Lastly, you may want to consider using the request library, as the request-promise library discourages the use of streams. See the github repo for more details: https://github.com/request/request-promise