2

Busboy is the middleware I'm using to upload a file. Using an html form inside Chrome, I can upload files (using the 'file' event) but when an android client tries to upload a file, it doesn't trigger the 'file' event, it triggers the 'field' event instead.

Here the code snippet I am using on the server side:

import express from 'express';
import busboy from 'connect-busboy';

const app = express();

const busUpload = (req, res)=> {
    req.busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
        saveTo = `${destination}/${filename}`;

        Log('uploading to', saveTo);
        file.pipe(fs.createWriteStream(saveTo));
        // file is saved successfully.
    });

    req.busboy.on('field', function(key, value, keyTruncated, valueTruncated) {
    //  I guess 'value' contains the file, but how do I save it? what is the name of file?
    });

    req.busboy.on('finish', function() {
        Log('upload completed');
        // res.writeHead(200, {'Connection': 'close'});
        res.json({sucess: true});
    });

    // req.pipe(req.busboy);

};

‍‍app.use('/uploads', busboy({immediate: true}), busUpload)

‍‍‍What's the difference? What should I tell the android developer to change in his request? Or how can I save the file inside the handler of the 'field' event?

Wilt
  • 41,477
  • 12
  • 152
  • 203
asedsami
  • 609
  • 7
  • 26

2 Answers2

1

According to the busboy documentation the file event is triggered for file uploads:

  • Emitted for each new file form field found. transferEncoding contains the 'Content-Transfer-Encoding' value for the file stream. mimeType contains the 'Content-Type' value for the file stream.

Since you get a field event my guess would be that the input is not sent similarly as in an html file input element:

<input type="file" name="filename" accept="media/type">

I am not familiar with android API so not sure how files are sent, but since your field event is triggered it seems you should dive into the client side (Android) of the code and see what possibilities you have.

Alternatively you can validate whether your field input contains a file like you already suggested in the code snippet in your question above:

//  I guess 'value' contains the file, but how do I save it? what is the name of file?

You can simply check what you get from your client by debugging/analyzing/logging your request object.


If you don't have the possibility to work on the client side code yourself, you could also try building a small html upload page where you upload files to your server and see what behavior you get. Like that you will be able to check easily if your server is working as expected. In this small application could upload files in different ways:

  1. through a form as in the example here
  2. as binary content as in the example here

And test whether your server is able to handle the file correctly in both cases.

Wilt
  • 41,477
  • 12
  • 152
  • 203
  • 1
    Thanks. I did log the `value` and it seems to be the buffer of the file which I don't think I can get the filename out of it. using `formidable` instead of `busboy`, and doing `console.log({fields, files})` I could understand that when I upload from browser, there is a key `filename`(as in ` – asedsami Aug 27 '18 at 07:19
  • You probably can get the file name from one of the request headers. Log your `req.headers` object and check what you get. Probably you will have a `content-disposition` header in there from which you can read the file name. – Wilt Aug 27 '18 at 07:23
  • Also check with your android developer whether he/she follows best practices for file uploading. It might be you get this unexpected behavior on your server because the code on the Android client is not following protocol. – Wilt Aug 27 '18 at 07:29
0

Simply put, a field event happens for any text field etc. Any data in form being passed in text field can be accessed via field event.

The file event occurs, if user uploads any file. The file can be accessed via registering event handler for file events and the file data can be read via data event in that.

so the code for file upload goes something like,

const bb = Busboy({ headers: req.headers });
bb.on('file', (name, file, info) => {
  let saveLocation = path.join(__dirname, '/');
  file.on('data', (data) => {
    console.log('some chunk received: ', data.length);
  })
  file.on('close',()=>{
    console.log('file reading done.')
  })
  file.pipe(fs.createWriteStream(saveLocation));
});
Hari Kishore
  • 2,201
  • 2
  • 19
  • 28