busboy not emitting field event - node.js

In the below code, I could see only the finish event emitting and not the field event.
const Busboy = require('busboy');
module.exports.controller = function(app) {
app.post('/api', function(req, res) {
var busboy = new Busboy({ headers: req.headers });
var formdata = {};
busboy.on('field', function (fieldname, val) {
console.log("fieldname : " + fieldname);
console.log("value : " + val);
formdata[fieldname] = val;
});
busboy.on('finish', function() {
res.send(formdata);
});
req.pipe(busboy);
});
};
As response, I receive {} back in postman. What could be possibly going wrong here?

I know this is long overdue, but I had this issue too and then I realized I was missing the name="" field in my HTML inputs.
Working snippet:
// handle form submissions
router.post('/submit', (req, res) => {
var busboy = new Busboy({ headers: req.headers });
busboy.on('field', function (fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) {
console.log('Field [' + fieldname + ']: value: ' + val);
});
busboy.on('finish', () => {
res.writeHead(303, { Connection: 'close', Location: '/' });
res.end();
});
req.pipe(busboy);
});

Related

Mutipart/form-data to JSON in Node.js using Busboy

I am working on an ios app which sends images and text to my firebase server using mutipart/form-data URLRequest. In order to process the data in my cloud function, I am using the method mentioned in documentation to parse the mutipart/form-data into JSON format, and here is my code:
const Busboy = require('busboy');
exports.test = functions.https.onRequest((req, res) => {
console.log("start");
console.log(req.rawBody.toString());
if (req.method === 'POST') {
var busboy = new Busboy({ headers: req.headers});
busboy.on('field', (fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) => {
console.log('field');
});
busboy.on('finish', function() {
console.log('finish');
res.json({
data: null,
error: null
});
});
req.pipe(busboy);
} else {
console.log('else...');
}
});
However, the above code doesn't seem to work, and here is the output from console:
Function execution started
start
--Boundary-43F22E06-B123-4575-A7A3-6C144C213D09
Content-Disposition: form-data; name="json"
{"name":"Alex","age":"24","friends":["John","Tom","Sam"]}
--Boundary-43F22E06-B123-4575-A7A3-6C144C213D09--
finish
Function execution took 517 ms, finished with status code: 200
As you can see, the on('field') function never execute. What did I miss?
Also, here is the code in swift for sending httpRequest:
var request = URLRequest(url: myCloudFunctionURL)
request.httpMethod = "POST"
request.setValue("multipart/form-data; boundary=myBoundary", forHTTPHeaderField: "Content-Type")
request.addValue(userToken, forHTTPHeaderField: "Authorization")
request.httpBody = myHttpBody
let session = URLSession.shared
session.dataTask(with: request) { (data, response, requestError) in
// callback
}.resume()
You will have to call busboy.end(req.rawBody); instead of req.pipe(busboy) as described in the example of the documentation. I dont know why .pipe doesnt work. Calling .end will produce the same result but with a different way.
const Busboy = require('busboy');
exports.helloWorld = functions.https.onRequest((req, res) => {
const busboy = new Busboy({ headers: req.headers });
let formData = {};
busboy.on('field', (fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) => {
// We're just going to capture the form data in a JSON document.
formData[fieldname] = val;
console.log('Field [' + fieldname + ']: value: ' + val)
});
busboy.on('finish', () => {
res.send(formData);
});
// The raw bytes of the upload will be in req.rawBody.
busboy.end(req.rawBody);
});
Enjoy this simple express middleware which converts all the Content-Type: multipart/form-data into you req.body in json format :)
const Busboy = require('busboy');
const expressJsMiddleware = (req, res, next) => {
const busboy = new Busboy({ headers: req.headers });
let formData = {};
busboy.on(
"field",
(fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) => {
formData = { ...formData, [fieldname]: val };
},
);
busboy.on("finish", () => {
req.body = formData;
next();
});
req.pipe(busboy);
};

How to view image in img tag

I got problem that i cant get this code to save to image in a img tag. the picture will only show the first time i enter the site, the next time i enter the site it is gone. guess its the pipe but is there a way to keep it there? have searched for days now...
this is my code to save it and get it.
router.post('/', function(req, res, next) {
var busboy = new Busboy({ headers : req.headers });
var fileId = new mongo.ObjectId();
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
console.log('got file', filename, mimetype, encoding);
var writeStream = gfs.createWriteStream({
_id: fileId,
filename: filename,
mode: 'w',
content_type: mimetype,
});
file.pipe(writeStream);
}).on('finish', function() {
// show a link to the uploaded file
res.writeHead(200, {'content-type': 'text/html'});
res.end('blogginnlegg1');
});
req.pipe(busboy);
});
//get file?
router.get('/file/:id', function(req, res, next){
gfs.findOne({ _id: req.params.id }, function (err, file) {
if (err) return res.status(400).send(err);
if (!file) return res.status(404).send('');
res.set('Content-Type', file.contentType);
res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
var readstream = gfs.createReadStream({
_id: file._id
});
readstream.on("error", function(err) {
console.log("Got error while processing stream " + err.message);
res.end();
});
readstream.pipe(res);
});
});

Nodejs sending file through http

I'm trying to send a file to another node.js service. So for that i'm using http and form-data modules.
This is the code i wrote
function uintToString(uintArray) {
return String.fromCharCode.apply(null, new Uint8Array(uintArray));
}
function (file) {
var data = uintToString(file.buffer);
//
var crlf = "\r\n",
boundaryKey = Math.random().toString(16),
boundary = `--${boundaryKey}`;
delimeter = `${crlf}--${boundary}`,
preamble = "", // ignored. a good place for non-standard mime info
epilogue = "",
headers = [
'Content-Disposition: form-data; name="file"; filename="' + name + '"' + crlf
],
closeDelimeter = `${delimeter}--`,
multipartBody = Buffer.concat(
new Buffer(preamble + delimeter + crlf + headers.join('') + crlf),
data,
new Buffer(closeDelimeter + epilogue)
);
var options = {
host: 'localhost',
port: 3000,
method: 'POST',
path: '/data/get',
headers: {
'Content-Type': 'multipart/form-data; boundary=' + boundary,
'Content-Length': formData._valueLength
}
};
//make request
return httpsRequest(formData, options)
.then((result) => {
console.log(result);
}, (err) => {
console.log(err);
});
};
function httpsRequest(data, options) {
return new Promise(function (resolve, reject) {
// request object
var req = https.request(options, function (res) {
var result = '';
res.on('data', function (chunk) {
result += chunk;
});
res.on('end', function () {
console.log("https end result - " + result);
resolve(result);
});
res.on('error', function (err) {
reject(err);
})
});
// req error
req.on('error', function (err) {
reject(err);
});
//send request witht the postData form
req.write(data);
req.end();
});
}
It is giving ""list" argument must be an Array of Buffers" this error. It looks like something is wrong on the httpsRequest function.
Don't reinvent the wheel, needle/request can do this for you. If you want to promisify things, use bluebird
const Promise = require('bluebird')
const needle = Promise.promisifyAll(require('needle'))
function send (file) {
let url = 'https://localhost/data/get'
let data = {
zip_file: {
buffer : file.buffer,
filename : name,
content_type : 'application/octet-stream'
}
}
return needle.postAsync(url, data, { multipart: true })
}

busboy not firing field, file event

In below code, only finish event called.
var Busboy = require('connect-busboy');
app.use(Busboy());
app.post('/fileupload', function(req, res) {
var fstream;
req.pipe(req.busboy);
req.busboy.on('error', function(err){
console.log(err);
});
req.busboy.on('field', function(fieldname, val, valTruncated, keyTruncated) {
console.log("fieldname: " + fieldname);
});
req.busboy.on('file', function (fieldname, file, filename) {
console.log("filename: " + filename);
fstream = fs.createWriteStream(__dirname + '/files/' + filename);
file.pipe(fstream);
fstream.on('close', function () {
res.redirect('back');
console.log("fileupload end");
});
});
req.busboy.on('finish', function() {
console.log('Done parsing form!');
});
});
The reason why you're not seeing any data is because you're already using the multer module which also parses multipart/form-data requests, saving files to disk. If you're not using multer and want to use busboy manually as you show in your code, you will need to remove the app.use(multer()); line.

How to remove incomplete uploaded file?

I am creating a node server to upload files using 'express','fs' and 'busboy' module. The server is working as expected but when I cancel the upload before complete, the incomplete file is stored in the filesystem. How can I remove the incomplete file?
var express = require("express"),
fs = require("fs"),
Busboy = require("busboy");
app = express();
app.listen(7000);
app.get("/", display_form);
app.post("/upload", function(req, res) {
var busboy = new Busboy({
headers: req.headers
});
busboy.on("file", function(fieldname, file, filename, encoding, mime) {
var fstream = fs.createWriteStream("./uploads/" + filename);
file.pipe(fstream);
file.on("data", function(chunk) {
console.log(chunk.length);
});
file.on("end", function() {
console("end");
});
fstream.on("close", function() {
fstream.close();
console("fstream close");
});
fstream.on("error", function() {
console("fstream error ");
});
});
busboy.on("finish", function() {
console.log("uploaded");
res.send("file uploaded");
});
busboy.on("error", function() {
console("error busboy");
});
req.pipe(busboy);
});
Thanks for your help and I finally I found a way to this problem. I added under mentioned code snippet and its working fine.
req.on("close", function(err) {
fstream.end();
fs.unlink('./uploads/' + name);
console.log("req aborted by client");
});
I don't know busboy, but you open a stream and never close it.
Why don't you exploit the stream and filename to 'finish' and 'error' and act accordingly?
Example:
busboy.on('error', function() {
fs.unlink('./uploads/' + filename);
console.log('error busboy');
}

Resources