27

I create my form like this:

form := url.Values{}
form.Add("region", "San Francisco")
if len(params) > 0 { 
    for i := 0; i < len(params); i += 2 { 
        form.Add(params[i], params[i+1])
    }
    testLog.Infof("form %v", form)

Now if I use

resp, err = http.PostForm(address+r.Path, form)

then everything works fine, I get back a response with an expected cookie.

However, I would like to to add a header in which case I can't use PostForm hence I created my POST request manually like:

req, err := http.NewRequest("POST", address+r.Path, strings.NewReader(form.Encode()))

Then I add stuff to the header and send the request

req.Header.Add("region", "San Francisco") 
resp, err = http.DefaultClient.Do(req)

But the form is not received and my response does not contain any cookie.

When I print the req, it looks like the form is nil:

&{POST http://localhost:8081/login HTTP/1.1 1 1 map[Region:[San Francisco]] {0xc420553600} 78 [] false localhost:8081 map[] map[] <nil> map[]   <nil> <nil> <nil> <nil>}
2
  • This is a webpage posting the form, right? You're gonna have to use JS for this if that is the case. When you're working with the template, Go code isn't posting anything, it's simply generating the html with an input element of type submit. That request on the other hand can't run in the browser, it's gotta run on the system. So if you have an html form using submit to POST to a Go back end and you want to add headers you need to use an XMLHttpRequest in JavaScript to accomplish that. Commented Oct 12, 2016 at 19:25
  • no, not a webpage, this is a Go unit test. See the answer below, setting the content-type in header fixed my problem. Commented Oct 12, 2016 at 21:18

1 Answer 1

55

You need to add a content type to your request.

You said http.PostForm worked so let's look at the source of that:

func PostForm(url string, data url.Values) (resp *Response, err error) {
    return DefaultClient.PostForm(url, data)
}

OK so it's just a wrapper around the PostForm method on the default client. Let's look at that:

func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) {
    return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}

OK it's calling the Post method and passing in "application/x-www-form-urlencoded" for bodyType and doing the same thing for the body that you're doing. Let's look at the Post method

func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
    req, err := NewRequest("POST", url, body)
    if err != nil {
        return nil, err
    }
    req.Header.Set("Content-Type", bodyType)
    return c.doFollowingRedirects(req, shouldRedirectPost)
}

So the solution to your problem is to add

req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.