func forwarderHandlerFunc(w http.ResponseWriter, r *http.Request) {
client := &http.Client{}
u, _ := url.Parse(r.RequestURI)
req, _ := http.NewRequest(r.Method, fmt.Sprintf("%s%s", apiUrl, u.Path), r.Body)
fmt.Printf(fmt.Sprintf("%s
", nutils.ReaderToString(req.Body)))
resp, _ := client.Do(req)
resp.Write(w)
}
I am trying to forward an incoming HTTP request to another endpoint, while copying the body, including POST/PUT form data into the new request.
However, it doesn't seem to work, even if the Body seems to print out correct with data.
Print output is:
email=meh%!g(MISSING)mail.com
How can I fix it?
Edit: Added more debug info, this time, printing out the output of resp
func forwarderHandlerFunc(w http.ResponseWriter, r *http.Request) {
client := &http.Client{}
u, _ := url.Parse(r.RequestURI)
req, _ := http.NewRequest(r.Method, fmt.Sprintf("%s%s", apiUrl, u.Path), r.Body)
fmt.Printf(fmt.Sprintf("%s
", nutils.ReaderToString(req.Body)))
resp, _ := client.Do(req)
b,_ := ioutil.ReadAll(resp.Body)
fmt.Printf(fmt.Sprintf("%s
", nutils.BytesToString(b)))
resp.Write(w)
}
$ go install && gom-proxy-forwarder run --listen localhost:5002 --api-url http://localhost:5001 email=meh2%!g(MISSING)mail.com { "email": null }
It should not be null. It should be meh@gmail.com
Got it. The problem was my endpoint in Python's Flask server does not support chunked encoding, which Go's Request insists on.
When I manually specified the ContentLength like req.ContentLength = 25
, it worked.
Lesson learnt: It might not always be your Go code be the problem.
You may want to set the request content type
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
reference http://golang.org/src/net/http/client.go?s=14234:14316#L450
To fix your print output you need to change this:
fmt.Printf(fmt.Sprintf("%s
", nutils.ReaderToString(req.Body)))
Into this:
fmt.Printf("%s", fmt.Sprintf("%s
", nutils.ReaderToString(req.Body)))
Or this:
fmt.Println(fmt.Sprintf("%s
", nutils.ReaderToString(req.Body)))
By printing out the request body you are consuming it. Use a TeeReader
:
req, _ := http.NewRequest(r.Method, fmt.Sprintf("%s%s", apiUrl, u.Path), io.TeeReader(r.Body, os.Stdout))
And get rid of the nutils.ReaderToString
call. You can only read once from a Reader
(unless it's also a Seeker
but then you still need to Seek
it before reusing it)