The package exposes a http.Client type that can be used to make requests. If the requests are simple GET or POST, then there are dedicated methods. The package also offers a function with the same name, but it's just a shorthand to the respective methods for the DefaultClient instance. Check the following code:
resp, err := http.Get("http://example.com/")
resp, err := client.Get("http://example.com/")
...
resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf)
resp, err := client.Post("http://example.com/upload", "image/jpeg", &buf)
...
values := url.Values{"key": {"Value"}, "id": {"123"}}
resp, err := http.PostForm("http://example.com/form", values)
resp, err := client.PostForm("http://example.com/form", values)
For any other kind of requirement, the Do method allows us to execute a specific http.Request. The NewRequest function allows us to specify any io.Reader:
req, err := http.NewRequest("GET", "http://example.com", nil)
// ...
req.Header.Add("Content-Type", "text/html")
resp, err := client.Do(req)
// ...
http.Client has several fields and many of these are interfaces that allows us to use the default implementation or a custom one. The first is CookieJar that allows the client to store and reuse web cookies. A cookie is a piece of data that the browser sends to the client and the client can send back to the server to replace headers, such as authentication. The default client does not use a cookie jar. The other interface is RoundTripper, which has only one method, RoundTrip, which gets a request and returns a response. There is a DeafultTransport value used if no value is specified that can also be used to compose a custom implementation of RoundTripper. http.Response returned by the client has also a body, which is io.ReadCloser, and its closure is the responsibility of the application. That's why it's recommended to use a deferred Close statement as soon as the response is obtained. In the following example, we will implement a custom transport that logs the requested URL and modifies one header before executing the standard round tripper:
type logTripper struct {
http.RoundTripper
}
func (l logTripper) RoundTrip(r *http.Request) (*http.Response,
error) {
log.Println(r.URL)
r.Header.Set("X-Log-Time", time.Now().String())
return l.RoundTripper.RoundTrip(r)
}
We will use this transport in a client that we will use to make a simple request:
func main() {
client := http.Client{Transport: logTripper{http.DefaultTransport}}
req, err := http.NewRequest("GET", "https://www.google.com/search?q=golang+net+http", nil)
if err != nil {
log.Fatal(err)
}
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
log.Println("Status code:", resp.StatusCode)
}