31

I am trying to upload a photo via a POST request with the request module

According to the readme I should just be able to do this

var r = request.post("http://posttestserver.com/post.php", requestCallback)
var form = r.form()
form.append("folder_id", "0");
form.append("filename", fs.createReadStream(path.join(__dirname, "image.png")));

function requestCallback(err, res, body) {
    console.log(body);
}

The problem is, this doesn't work. I get a reply from the test server saying it dumped 0 post variables.

I have confirmed that the server is in working condition with this little html page

<html>
    <body>
        <form action="http://posttestserver.com/post.php?dir=example" method="post" enctype="multipart/form-data">
            File: <input type="file" name="submitted">
            <input type="hidden" name="someParam" value="someValue"/>
            <input type="submit" value="send">
        </form>
    </body>
</html>

So the question is, what am I doing wrong with the request module? Is there a better way to send multipart/form-data with node?

giodamelio
  • 5,465
  • 14
  • 44
  • 72

5 Answers5

28

After some more research, I decided to use the restler module. It makes the multipart upload really easy.

fs.stat("image.jpg", function(err, stats) {
    restler.post("http://posttestserver.com/post.php", {
        multipart: true,
        data: {
            "folder_id": "0",
            "filename": restler.file("image.jpg", null, stats.size, null, "image/jpg")
        }
    }).on("complete", function(data) {
        console.log(data);
    });
});
giodamelio
  • 5,465
  • 14
  • 44
  • 72
  • 1
    Make sure the following statement at import section var fs = require('fs'); – webjockey Jan 10 '13 at 05:15
  • 1
    Getting the file size: var fs = require('fs'); var fileStats = fs.statSync('/myFile.jpg'); var fileSizeInBytes = fileStats["size"]; console.log(fileStats); console.log(fileSizeInBytes); – Adam Mendoza Jan 31 '15 at 02:03
  • I am getting error if file size is more than 2 mb. what should I modify in code ? –  Feb 16 '17 at 08:38
  • Many PHP servers have an upload limit of 2mb. Can you upload a larger file directly using the form? If not then it is a server limitation that your code can not overcome. – Nate Bunney Feb 05 '18 at 20:22
18

So I just got done wrestling with this myself and here is what I learned:

It turns out that neither request or form-data are setting the content-length header for the generated body stream.

Here is the reported issue: https://github.com/mikeal/request/issues/316

The solution posted by @lildemon gets around this by:

  1. Generating the FormData object
  2. Getting it's length
  3. Making the request and setting the form object and content-length header explicitly

Here is a modified version of your example:

var request = require('request');
var FormData = require('form-data');

var form = new FormData();
form.append("folder_id", "0");
form.append("filename", fs.createReadStream(path.join(__dirname, "image.png")));

form.getLength(function(err, length){
  if (err) {
    return requestCallback(err);
  }

  var r = request.post("http://posttestserver.com/post.php", requestCallback);
  r._form = form;     
  r.setHeader('content-length', length);

});

function requestCallback(err, res, body) {
  console.log(body);
}
ianmetcalf
  • 181
  • 1
  • 2
5

I have working code that does exactly what your question states, with one exception. My file content is appended this way:

form.append('file', new Buffer(...),
    {contentType: 'image/jpeg', filename: 'x.jpg'});

To discover the final options argument I had to drill down into the source of form-data. But this gives me a working configuration. (Maybe it was what you were missing, but of course that will depend on the server.)

wberry
  • 18,519
  • 8
  • 53
  • 85
  • 1
    I was going to embark on this journey but you just saved me the trouble. ty! 7 years later it is still not well documented – sp3c1 May 13 '21 at 13:17
3

I tried also request and form-data modules and was unable to upload a file. You can use superagent which works:

http://visionmedia.github.io/superagent/#multipart-requests.

var request = require('superagent');
var agent1 = request.agent();
agent1.post('url/fileUpload')
      .attach('file',__dirname + "/test.png")
      .end(function(err, res) {
          if (err) {
              console.log(err)
           }
       });
Miroslaw Dylag
  • 271
  • 2
  • 4
0

Try request module. It works like any other normal post request

var jsonUpload = {  };
var formData = {
    'file': fs.createReadStream(fileName),
    'jsonUpload': JSON.stringify(jsonUpload)
};
var uploadOptions = {
    "url": "https://upload/url",
    "method": "POST",
    "headers": {
        "Authorization": "Bearer " + accessToken
    },
    "formData": formData
}
var req = request(uploadOptions, function(err, resp, body) {
    if (err) {
        console.log('Error ', err);
    } else {
        console.log('upload successful', body)
    }
});
Gautam
  • 743
  • 7
  • 9
  • When posting this to another service's url, the readStream property disappears from the payload and no events on the request are detected on the receiving end. Any ideas why? – Alexander Swann Jan 23 '18 at 16:54