18

I am trying to pass a request object from my routes to a controller which processes the uploads,

here is the route -

app.post('/upload/notes',auth.requiresApiLogin,function(req,res){
        upload.file(req,res);
});

here is the controller (upload.js) code which has the exported file method

var fs = require('fs'),
    uuid = require('node-uuid'),
    path = require('path'),
    Busboy = require('busboy');
exports.file = function(req, res) {
    var busboy = new Busboy({ headers: req.headers});
    busboy.on('file', function(fieldname, file, filename,transferEncoding,mimeType) {
        console.log("inside upload function");
        console.log(file);
    });
    busboy.on('field', function(fieldname, val, valTruncated,keyTruncated) {
        console.log("inside field function");
        console.log(fieldname);
    });
    busboy.on('finish',function(){
        console.log('finished');
    });
    req.pipe(busboy);
//
//    req.pipe(req.busboy);
//    req.busboy.on('file', function(fieldname, file, filename,transferEncoding,mimeType) {
//        var fName = uuid.v4();
//        console.log(filename);
//        var fileext = filename.substr(filename.lastIndexOf('.') + 1);
//
//        console.log(transferEncoding);
//        console.log(mimeType);
//        var filepath = path.normalize(__dirname + '/../../');
//        var fstream = fs.createWriteStream(filepath+'/server/uploads/'+fName+'.'+fileext);
//        file.pipe(fstream);
//        fstream.on('close', function () {
//            res.redirect('back');
//        });
//    });
};

So, what i see that both the fields and the files are being logged in console but the finish event is not getting fired. What else should i try ?

Harshit Laddha
  • 2,044
  • 8
  • 34
  • 64

2 Answers2

49

You need to consume the file stream somehow. For testing purposes you can ignore the data by adding file.resume(); inside the file event handler.

mscdex
  • 104,356
  • 15
  • 192
  • 153
  • aren't you the author of busboy? thanks that was the mistake i was making. – Harshit Laddha Jul 05 '14 at 16:36
  • 10
    Yes, I am the author. – mscdex Jul 05 '14 at 17:12
  • Hey, I wanted to ask if the fields,val received in the field event are read only or something like that? because I am passing an object from angular to the busboy and then when i receive it has all the data, but lets say if the val is the object then if i try something like val.a="b"; where a is some new property i want to add i still get undefined for val.a if i log it, it is still the same object i recieved – Harshit Laddha Jul 06 '14 at 05:12
  • 1
    values passed to 'field' event handlers are merely strings, so the js engine is probably restricting changes to the string. – mscdex Jul 06 '14 at 14:40
  • Oh, yeah found it when i logged in the type of the val. so had to use JSON.parse(val) first to create a object from the string. thanks for the help – Harshit Laddha Jul 06 '14 at 19:54
  • can you please help me with this question - http://stackoverflow.com/questions/24632474/checking-if-busboy-finish-event-has-already-occured-or-not – Harshit Laddha Jul 08 '14 at 18:29
5

This answer might help someone who wants to consume the file...

Make sure to pass control back to express by calling next() in the finish method after consuming the file e.g.

app.use(function(req: Request, res: ServerResponse, next:any) {
let bb = new busboy({ headers: req.headers });
let fileData: any = null;
const fieldArray: any = [];
let dataLength: number;
const extractFields =  (name: string, val: any, data: any) => {
  if (Array.isArray(data[name])) {
    data[name].push(val);
  } else if (data[name]) {
    data[name] = [data[name], val];
  } else {
    data[name] = val;
  }
};
bb.on('field', function(fieldname: string, val:any, fieldnameTruncated: boolean, valTruncated: boolean, encoding: string, mimetype: string) {
  // extract fields to add to req body for later processing
  extractFields(fieldname, val, fieldArray);
  console.log('Field [' + fieldname + ']: value: ' + val);

});

bb.on('file', function(fieldname: string, file: NodeJS.ReadableStream , filename: string, encoding: string, mimetype: string) {
  file.on('data', function(data) {
    console.log('File [' + fieldname + '] got ' + data.length + ' bytes');
    // Process buffer to save complete file to add to the req for access later
    if (fileData === null) {
      fileData = data;
    } else {
      fileData = Buffer.concat([fileData, data]);
    }
  });
  file.on('end', function() {
    console.log('File [' + fieldname + '] Finished');
  });
});

bb.on('finish', function() {
  req.body = fieldArray
  req.body.files = {file: fileData};
  console.log('Done parsing form!');
  next(); // <- Allows processing to continue and avoids request hanging
});

bb.on('close', () => {
console.log('Event closed')
});
// what does this do? Send the readable request stream to busboy which is a writeable stream. The above code dictates to the writeable
// how to respond when certain events are fired during the pipe.
req.pipe(bb);
});
Norbert
  • 809
  • 9
  • 13
  • Would I need to consume the file if I just wanted to take it from an API and store it in a database? – jdost_26 May 31 '23 at 03:12