Unable to read entire response body - http

I'm trying to make a straightforward request to an API, which works just fine in Postman, and weirdly occasionally works in my app, but usually fails when trying to parse the JSON because only about half the response is being read into the body variable. When the entire response is read everything works fine. I'm not really sure what if anything I'm doing wrong here, or if there's anything else I can do differently to make sure that the entire response is parsed.
var reqBody = []byte(fmt.Sprintf(`{
"methodName": "GetPropertyList",
"params": {
"token_key": "%v",
"token_secret": "%v"
}
}`, token, secret))
req, err := http.NewRequest("POST", proxy_url, bytes.NewBuffer(reqBody))
req.Header.Set("Content-Type", "application/json")
client := http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Printf("Couldn't get property field list: %v")
} else {
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
bodyStr := string(body)
log.Printf("BODY: %v", len(bodyStr))
var respModel ResponseModel
err = json.Unmarshal(body, &respModel) //Error happens here
}

you can do it by using json.NewDecoder(resp.Body).Decode(&respModel)
The full code would then look like:
var token, secret, proxy_url string
var reqBody = []byte(fmt.Sprintf(`{
"methodName": "GetPropertyList",
"params": {
"token_key": "%v",
"token_secret": "%v"
}
}`, token, secret))
req, err := http.NewRequest("POST", proxy_url, bytes.NewBuffer(reqBody))
req.Header.Set("Content-Type", "application/json")
client := http.Client{}
var respModel ResponseModel
resp, err := client.Do(req)
if err != nil {
log.Printf("Couldn't get property field list: %v", err)
} else {
err := json.NewDecoder(resp.Body).Decode(&respModel)
}

Related

Go http request redirect

I am writing an API whichs has to redirect incoming requests to another service, the response must be forwarded to the original requester.
I figured a simple function like below should do the trick, but I was wrong.
I receive the data from my redirected response, however when I send it back to the initial request I receive this response without any data Could not get response. Error: socket hang up
If I try to execute the very same request using postman straight to the redirect URL it works perfectly fine.
func initialAssetsHandler(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
fmt.Println(err)
return
}
resp, err := http.Post(conf.redirectURL, "application/json", bytes.NewReader(body))
if err != nil {
log.Error(err)
}
defer resp.Body.Close()
buf := new(bytes.Buffer)
buf.ReadFrom(resp.Body)
log.Info(string(buf.Bytes()))
var data json.RawMessage
if err = json.NewDecoder(resp.Body).Decode(&data); err != nil {
fmt.Println(err)
return
}
helper.SendJsonRaw(w, 200, data)
}
Here is the SendJsonRaw function:
func SendJsonRaw(w http.ResponseWriter, status int, r json.RawMessage) error {
w.Header().Set(HeaderContentType, MimeApplicationJSON)
w.WriteHeader(status)
_, err := w.Write(r)
return err
}
The r.Body is read by the json decoder up to EOF, then when you pass it to the redirect request it looks empty to the http.Client and therefore it sends no body. You need to retain the content of the body.
For example you can do the following:
func initialAssetsHandler(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
fmt.Println(err)
return
}
var initialAssets TagAssets
if err := json.Unmarshal(&initialAssets, body); err != nil {
if !strings.Contains(err.Error(), "json: invalid use of ,string struct tag, trying to unmarshal") {
helper.SendJsonError(w, http.StatusBadRequest, err)
return
}
}
resp, err := http.Post(conf.redirectURL, "application/json", bytes.NewReader(body))
if err != nil {
log.Error(err)
}
defer resp.Body.Close()
log.Info(resp)
var data json.RawMessage
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
fmt.Println(err)
return
}
helper.SendJsonOk(w, data)
}

Convert string from args/flags to json then send to post http request as body

I'm trying to pass the values ​​I get in the arg / flag --BODY="{user: root}" as the body of the post request I'm trying to do, I've already used json.Marshal and even so I wasn't successful, thanks for the help !
Code below:
func Custom(method string, url string, token string, data string) {
req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
req.Header.Add("Authorization", FormatBearerToken(token))
// req.Header.Set("Content-Type", "application/json")
if err != nil {
log.Println("Request failed, ", err)
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Println(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
log.Println("response Body:", string(body))
}

How to send post form data through a http client?

I have a problem with post request, needed to send simple form data through http client.
http.PostForm() is not ok because I need to set my own user agent and other headers.
Here is the sample
func main() {
formData := url.Values{
"form1": {"value1"},
"form2": {"value2"},
}
client := &http.Client{}
//Not working, the post data is not a form
req, err := http.NewRequest("POST", "http://test.local/api.php", strings.NewReader(formData.Encode()))
if err != nil {
log.Fatalln(err)
}
req.Header.Set("User-Agent", "Golang_Super_Bot/0.1")
resp, err := client.Do(req)
if err != nil {
log.Fatalln(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}
log.Println(string(body))
}
You also need to set the content type to application/x-www-form-urlencoded which corresponds to the encoding used by Value.Encode().
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
This is mentioned as one of the things done by Client.PostForm.

How to properly set path params in url using golang http client?

I'm using net/http package and i would like to set dynamic values to an POST url:
http://myhost.com/v1/sellers/{id}/whatever
How can i set id values in this path parameter?
You can use path.Join to build the url. You may also need to pathEscape the path-params received externally so that they can be safely placed within the path.
url1 := path.Join("http://myhost.com/v1/sellers", url.PathEscape(id), "whatever")
req, err := http.NewRequest(http.MethodPost, url1, body)
if err != nil {
return err
}
If you are trying to add params to a URL before you make a server request you can do something like this.
const (
sellersURL = "http://myhost.com/v1/sellers"
)
q := url.Values{}
q.Add("id", "1")
req, err := http.NewRequest("POST", sellersURL, strings.NewReader(q.Encode()))
if err != nil {
return err
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Close = true
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}

Golang: Simultaneous function Calls for http post request

I need to call multiple URL at the same time. My functions get called at the same time (in milli seconds) but the moment I add a Http post request to the code it gets called one after the other. Below is the code:
Check(url1)
Check(url2)
func Check(xurl string) {
nowstartx := time.Now()
startnanos := nowstartx.UnixNano()
nowstart := startnanos / 1000000
fmt.Println(nowstart)
json = {"name" : "test"}
req, err := http.NewRequest("POST", xurl, bytes.NewBuffer(json))
req.Header.Set("X-Custom-Header", "myvalue")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
} else {
defer resp.Body.Close()
body, _ = ioutil.ReadAll(resp.Body)
}
}
Appreciate help, I need to get the same time (in milliseconds) when I run the program.
This is achieved by using Goroutines
go Check(url1)
go Check(url2)
func Check(xurl string) {
nowstartx := time.Now()
startnanos := nowstartx.UnixNano()
nowstart := startnanos / 1000000
fmt.Println(nowstart)
json = {"name" : "test"}
req, err := http.NewRequest("POST", xurl, bytes.NewBuffer(json))
req.Header.Set("X-Custom-Header", "myvalue")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
} else {
defer resp.Body.Close()
body, _ = ioutil.ReadAll(resp.Body)
}
}

Resources