HTTP Client
suggest changePackage net/http
in standard library provides functionality to make HTTP network requests.
In the examples we use httpbin.org which is a clever service that can return specific HTTP responses, which is useful for demonstrating various aspects of HTTP protocol.
Basic HTTP GET
For simplicity this example uses http.Get()
. In real programs you should use custom client with a timeout as described below.
uri := "https://httpbin.org/html"
resp, err := http.Get(uri)
if err != nil {
log.Fatalf("http.Get() failed with '%s'\n", err)
}
// it's important to close resp.Body or else we'll leak network connection
// it must be done after checking for error because in error case
// resp.Body can be nil
defer resp.Body.Close()
d, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalf("ioutil.ReadAll() failed with '%s'\n", err)
}
contentType := resp.Header.Get("Content-Type")
fmt.Printf("http.Get() returned content of type '%s' and size %d bytes.\nStatus code: %d\n", contentType, len(d), resp.StatusCode)
// getting page that doesn't exist return 404
uri = "https://httpbin.org/page-doesnt-exist"
resp, err = http.Get(uri)
if err != nil {
log.Fatalf("http.Get() failed with '%s'\n", err)
}
contentType = resp.Header.Get("Content-Type")
fmt.Printf("\nhttp.Get() returned content of type '%s' and size %d bytes.\nStatus code: %d\n", contentType, len(d), resp.StatusCode)
// acessing non-existent host fails
uri = "http://website.not-exists.as/index.html"
resp, err = http.Get(uri)
if err != nil {
fmt.Printf("\nhttp.Get() failed with: '%s'\nresp: %v\n", err, resp)
}
This shows how to make HTTP GET request for a URL (HTML page in this case).
I use uri
as variable name because there is net/url
package which means using more natural url
will lead to naming conflicts when importing net/url
in the same file.
When there is no error, http.Get()
returns *http.Response
with notable fields:
Body
isio.Reader
containing content of the response. If the URL was HTML page, this is HTML data. If the URL was PNG image, this is PNG dataStatusCode
is anint
describing HTTP status code. 200 means OK. 404 means Not Found etc.Header
contains response headers. Its type ismap[string][]string
because per HTTP spec it’s ok to have multiple headers with the same name
When no error is returned, it’s important to resp.Body.Close()
or you will leak resources.
Trying to access page that doesn’t exist on the server returns a response with StatusCode
404 (Not Found).
Trying to access non-existent host will fail, in which case response is nil
.
HTTP GET using custom client
http.Get()
is just a wrapper that delegates all work http.DefaultClient
, which is a package variable of type *http.Client
.
It’s best not to use http.Get
because default client doesn’t have a timeout, which means it’ll wait forever connecting to slow or buggy or malicious servers.
client := &http.Client{}
client.Timeout = time.Millisecond * 100
uri := "https://httpbin.org/delay/3"
resp, err := client.Get(uri)
if err != nil {
log.Fatalf("http.Get() failed with '%s'\n", err)
}
As shown, creating and using custom http.Client
is easy.
In this example we set a very short time-out to demonstrate that exceeding this timeout cancels the connection.
In real programs we would use longer timeout, like 15 seconds (the exact timeout depends on particulars of your code).
Basic HTTP POST
client := &http.Client{}
client.Timeout = time.Second * 15
uri := "https://httpbin.org/post"
body := bytes.NewBufferString("text we send")
resp, err := client.Post(uri, "text/plain", body)
if err != nil {
log.Fatalf("client.Post() failed with '%s'\n", err)
}
defer resp.Body.Close()
d, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalf("http.Get() failed with '%s'\n", err)
}
fmt.Printf("http.Post() returned statuts code %d, truncated text:\n%s...\n", resp.StatusCode, string(d)[:93])
The simplest way to do POST is using http.Client.Post(url string, contentType string, body io.Reader)
.
In this example we send raw text. Most of the time the server expects body to be in url-encoded format.
Basic HTTP HEAD
Like HTTP GET but use http.Client.Head(uri string)
method.