Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP POST w/ body troubles #8

Closed
boxxxie opened this issue Dec 8, 2012 · 18 comments
Closed

HTTP POST w/ body troubles #8

boxxxie opened this issue Dec 8, 2012 · 18 comments

Comments

@boxxxie
Copy link

boxxxie commented Dec 8, 2012

I can do a post without a body, ei, basic auth. when i add a body i run into lots of problems (post stalls, or doesn't get sent or get's sent but doesn't make sense)

var api_login_req = {
            url: urls.api.session.post,
            headers: _.pick(req.headers, 'authorization'),
            method: "POST",
            body:"osdijfoisdjfosdf"
        };

        return HTTP.
        request(api_login_req).

the body in the above code causes this request to stall, it doesn't get sent at all. when i comment out the body eveything is ok.

looking in the Qhttp code i see that that body needs a forEach. however i'm not sure if Q.when(req.body... would transform it into something with a forEach... anyway i changed my body into this:

var api_login_req = {
            url: urls.api.session.post,
            headers: _.pick(req.headers, 'authorization'),
            method: "POST",
            body:["osdijfoisdjfosdf"]
        };

        return HTTP.
        request(api_login_req).

and my post gets sent. however on the receiving end (using connect, w/ bodyParser) my req.body is empty.

it would be great to have an example of how to use this function.

@kriskowal
Copy link
Owner

I’ll write up a test case and see what the problem is. The array is the preferred output, but I might adjust normalizeRequest and normalizeResponse to accept a string.

@karlwestin
Copy link

Hi, i've been looking at a similar thing, you'll need to use a "Content-Type": "application-/x-www-form-urlencoded" header.
this worked:

// server.js
var connect = require("connect");
var server = connect(connect.bodyParser());

function file(req, res, next) {
  if(req.method == "POST") {
    console.log("req", req.body, req);
    res.writeHead(200);
    res.end("hi");
  }
}

server.use(file);
module.exports = server;
server.listen(3000);

//------------------------------
// client.js
var fs = require("q-io/fs");
var http = require("q-io/http");
fs.read("./ha.txt").then(function(text) {
  var request = {
     host: "localhost",
     port: 3000,
     method: "POST",
     body: [text],
     headers: { "Content-Type": "application/x-www-form-urlencoded" }
  };
  return http.request(request);
}).then(function(resp) {
  return console.log("uploaded");
}).fail(function(err) {
  console.log("failed", err);
});

@kriskowal
Copy link
Owner

@boxxxie can you verify and close?

@boxxxie boxxxie closed this as completed Dec 31, 2012
@kriskowal
Copy link
Owner

Thanks!

@boxxxie
Copy link
Author

boxxxie commented Dec 31, 2012

I'm not on nodejs anymore so I can't easily confirm. However if your code works then that would be really helpful for people like me building multi system applications.

@wmertens
Copy link
Collaborator

I had to do something like (coffeescript)

request = 
  url: url,
  method: 'POST'
  body: [("#{key}=#{encodeURIComponent value}" for key, value of formData).join '&']
  headers: "Content-Type": "application/x-www-form-urlencoded"

return HTTP.read(request).then( (body) -> JSON.parse body )

It would be nice if q-io could include some sugar to make form passing easy... A project like https://github.com/mikeal/request is of course a lot more complete but how about something like adding a form key to a request that will convert into the body and headers as above? That's only a few lines of code... Likewise a readJson would be nice?

@cerebrl
Copy link

cerebrl commented Nov 5, 2013

From what I can tell, this is still very much an issue. It took me hours to realize that any truthy value in the body of the request fails, except for an array. Unfortunately, the receiving end of the request has no body, so the array value is not being passed through. This should be documented somewhere, please! I can't count how many hours I've wasted trying to debug this :(

@kriskowal
Copy link
Owner

@cerebrl Can you confirm that the problem was that you passed a string for a request body instead of an array? I will consider fixing that. I definitely intend to produce better documentation. The stuff I have is far too rough and it looks like the users are coming.

@cerebrl
Copy link

cerebrl commented Nov 5, 2013

Hey Kris! Thanks for the quick reply. The request does go through if I pass an array into the body. But, on the receiving end of the request, req.body is undefined. I don't know what happens to the array, but it never shows up on the other side [shrugs]

@kriskowal
Copy link
Owner

@cerebrl That is curious. Can you send me a gist or more details about the scenario. Are your client and server both Node.js processes?

@cerebrl
Copy link

cerebrl commented Nov 5, 2013

I'll try to write you up a gist tomorrow. It's getting a bit late tonight :) Thanks!

@kriskowal
Copy link
Owner

I’ll be here. Thanks!

@cerebrl
Copy link

cerebrl commented Nov 5, 2013

Well, I couldn't help myself: https://gist.github.com/cerebrl/7314665

Let me know if I'm doing something wrong here or if you have any questions.

@kriskowal
Copy link
Owner

Thanks, that’s insightful.

@OliverJAsh
Copy link
Contributor

The reason it does not error if the body is not an instance of Array is because there was a missing end to a promise chain.

@newtriks
Copy link

I was having similar odd issues when posting JSON data to my Rails based api. I did manage to get it working using the above suggestion "Content-Type": "application-/x-www-form-urlencoded", however, I really wanted to persist and fathom out why the JSON body appeared to be empty.

The solution I found after trial and error, revealed two interesting results which may or maybe not obvious to others:

  1. Adding Content-Length to headers ensures that the JSON is passed in the body.
  2. Posting an empty body results in a socket hang up error.

Here is the code I used which successfully makes a POST request with JSON data within the request body:

var body = JSON.stringify({
        token: 'foo',
        files: files // Array of filenames
    });

    var headers = {
        'Content-Type': 'application/json',
        'Content-Length': Buffer.byteLength(body, 'utf8')
    };

    var request = {
        url: apiURL,
        charset: 'UTF-8',
        method: 'POST',
        headers: headers,
        body: [body]
    };

    return http.request(request)
        .then(function (response) {
            var ok = response.status >= 200 && response.status < 400;
            if (!ok) {
                throw new Error('API responded with a status code: ' + response.status);
            }
        });

@doapp-ryanp
Copy link

@newtriks thanks for the example. FWIW I did not need to set the Content-Length header.

@jonahbron
Copy link

@newtriks Thanks for that example. As soon as I added the content-length, it worked 😦

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants