I'm doing a simple http GET in Go:
client := &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
res, _ := client.Do(req)
But I can't found a way to customize the request header in the doc, thanks
The Header field of the Request is public. You may do this :
req.Header.Set("name", "value")
Pay attention that in http.Request header "Host" can not be set via Set method
req.Header.Set("Host", "domain.tld")
but can be set directly:
req.Host = "domain.tld":
req, err := http.NewRequest("GET", "http://10.0.0.1/", nil)
if err != nil {
...
}
req.Host = "domain.tld"
client := &http.Client{}
resp, err := client.Do(req)
If you want to set more than one header, this can be handy rather than writing set statements.
client := http.Client{}
req , err := http.NewRequest("GET", url, nil)
if err != nil {
//Handle Error
}
req.Header = http.Header{
"Host": {"www.host.com"},
"Content-Type": {"application/json"},
"Authorization": {"Bearer Token"},
}
res , err := client.Do(req)
if err != nil {
//Handle Error
}
Go's net/http package has many functions that deal with headers. Among them are Add, Del, Get and Set methods. The way to use Set is:
func yourHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("header_name", "header_value")
}
Related
Basically, I need to implement the following method in Go - https://api.slack.com/methods/users.lookupByEmail.
I tried doing it like this:
import (
"bytes"
"encoding/json"
"errors"
"io/ioutil"
"net/http"
)
type Payload struct {
Email string `json:"email,omitempty"`
}
// assume the following code is inside some function
client := &http.Client{}
payload := Payload{
Email: "octocat#github.com",
}
body, err := json.Marshal(payload)
if err != nil {
return "", err
}
req, err := http.NewRequest("GET", "https://slack.com/api/users.lookupByEmail", bytes.NewReader(body))
if err != nil {
return "", err
}
req.Header.Add("Authorization", "Bearer "+token)
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
t, _ := ioutil.ReadAll(resp.Body)
return "", errors.New(string(t))
}
responseData, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(responseData), nil
But I get an error that "email" field is missing, which is obvious because this content-type does not support JSON payload:
{"ok":false,"error":"invalid_arguments","response_metadata":{"messages":["[ERROR] missing required field: email"]}} (type: string)
I couldn't find how to include a post form with the GET request - there is no available post form argument neither to http.NewRequest, nor to http.Client.Get; http.Client.PostForm issues a POST request but GET is needed in this case. Also, I think I have to use http.NewRequest here (unless another approach exists) because I need to set the Authorization header.
You misunderstand the application/x-www-form-urlencoded header, you should pass an URL parameters here. Check out an example:
import (
...
"net/url"
...
)
data := url.Values{}
data.Set("email", "foo#bar.com")
data.Set("token", "SOME_TOKEN_GOES_HERE")
r, _ := http.NewRequest("GET", "https://slack.com/api/users.lookupByEmail", strings.NewReader(data.Encode()))
r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
r.Header.Add("Content-Length", strconv.Itoa(len(data.Encode())))
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.
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
}
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)
}
}
I am writing a wrapper for an API in go. The api uses basic auth and then POST request requires PostForm value. I'm doing something like this:
func NewFoo(name string) string {
client := &http.Client{}
URL := HOST + "foo/"
req, err := http.NewRequest("POST", URL, nil)
v := url.Values{}
v.Set("name", name)
req.Form = v
req.SetBasicAuth(EMAIL, PASSWORD)
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
bodyText, err := ioutil.ReadAll(resp.Body)
s := string(bodyText)
return s
}
I had a similar, GET request without the form value and it works. When I run it, it tells me that the "name" value is required. (so it's not getting it)
Is there any reason this does not work?
From http://golang.org/pkg/net/http/#Request
// Form contains the parsed form data, including both the URL
// field's query parameters and the POST or PUT form data.
// This field is only available after ParseForm is called.
// The HTTP client ignores Form and uses Body instead.
Form url.Values
You have to pass your url.Values to the request's body instead.
func NewFoo(name string) string {
client := &http.Client{}
URL := HOST + "foo/"
v := url.Values{}
v.Set("name", name)
//pass the values to the request's body
req, err := http.NewRequest("POST", URL, strings.NewReader(v.Encode()))
req.SetBasicAuth(EMAIL, PASSWORD)
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
bodyText, err := ioutil.ReadAll(resp.Body)
s := string(bodyText)
return s
}