8

I am currently receiving a file encoded as a base64 string as part of a json payload:

{
    "file":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPGRlZmluaXRpb25zIHhtb..."
}

With that string I am supposed to post the file as multipart/form-data to a different service so I have a method like this (using request module):

var request = require('request');
var fs = require('fs');

var importFile = function(fileBase64Encoded, cb) {
    var decodedFile = new Buffer(fileBase64Encoded, 'base64');
    var r = request.post('http://localhost:8888/upload', function (err, httpResponse, body) {
        if (err) {
            cb(err);
        }
        cb(null, body);
    });
    var form = r.form();
    form.append('file', decodedFile);
}

And this is currently not working. If I write file to disk and read it from there like this:

var request = require('request');
var fs = require('fs');

var importFile function(fileBase64Encoded, cb) {

    var decodedFile = new Buffer(fileBase64Encoded, 'base64');
    fs.writeFile('temp.txt', decodedFile, function (err) {
        if (err) return console.log(err);
        var r = request.post('http://localhost:8888/upload', function (err, httpResponse, body) {
            if (err) {
                cb(err);
            }
            cb(null, body);
        })
        var form = r.form();
        form.append('file', fs.createReadStream('temp.txt'));
    });

}

Then it works...so Is there a real way to pass the base64 string as a valid parameter to the form? (right now trying with a buffer and not working)

jdrm
  • 621
  • 2
  • 8
  • 21

1 Answers1

13

I assume that http://localhost:8888/upload is expecting file to be ... a "file". When you pass a file stream to form.append() it already knows it's a "file". When passing a Buffer it does not.

You can, however, tell form.append() to interpret your Buffer as a "file" by passing an options object as the third argument. The options object should have a key called filename containing a string with the name of the file. Optionally, the object can also include a contentType string and knownLength integer. If contentType is not included, form.append() will try to derive the content-type from the filename.

Other than to determine contentType (when it is not explicitly passed in the options argument), the filename you specify is irrelevant (i.e. you can use whatever file name you want). Unless, of course, you intend to use the filename on the server-side code.

In your case, the following should work.

var importFile = function(fileBase64Encoded, cb) {
    var decodedFile = new Buffer(fileBase64Encoded, 'base64');
    var r = request.post('http://localhost:8888/upload', function (err, httpResponse, body) {
        if (err) {
            cb(err);
        }
        cb(null, body);
    });
    var form = r.form();
    form.append('file', decodedFile, { filename: 'temp.txt' });
}
JME
  • 3,592
  • 17
  • 24
  • When you are calling request.post(), is the post request already fired? How do you fire it after appending? – Sisir Oct 31 '18 at 11:07
  • @Sisir ... `request.post()` fires automatically during the next cycle of the event loop. Any changes to `r` (the request object) will can be done before the next cycle is triggered. – JME Nov 28 '18 at 03:19