Upgrade to Pro — share decks privately, control downloads, hide ads and more …

net/http package ~GoConference 2017 Spring~

net/http package ~GoConference 2017 Spring~

Shintaro Kaneko

March 25, 2017
Tweet

More Decks by Shintaro Kaneko

Other Decks in Programming

Transcript

  1. kaneshin (Shintaro Kaneko) - CTO of Eureka, Inc. - Twitter:

    @kaneshin0120 - Gopher, Vimmer, Photographer, Mathematician
  2. Today's special var sleepHandler = func(w http.ResponseWriter, r *http.Request) {

    time.Sleep(time.Hour) w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body)
  3. net/http/httptest var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body)
  4. net/http/httptest var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) http://blog.kaneshin.co/entry/2016/12/02/200108 net/http/httptest.Server net/http/httptest.ResponseRecorder
  5. net/http/httptest var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body)
  6. net/http.ResponseWriter var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body)
  7. net/http.ResponseWriter var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } type ResponseWriter interface { // Changing the header map after a call to WriteHeader (or // Write) has no effect unless the modified headers are trailers. Header() Header Write([]byte) (int, error) // If WriteHeader is not called explicitly, the first call to Write // will trigger an implicit WriteHeader(http.StatusOK). WriteHeader(int) }
  8. net/http.ResponseWriter var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } type ResponseWriter interface { // Changing the header map after a call to WriteHeader (or // Write) has no effect unless the modified headers are trailers. Header() Header Write([]byte) (int, error) // If WriteHeader is not called explicitly, the first call to Write // will trigger an implicit WriteHeader(http.StatusOK). WriteHeader(int) }
  9. net/http.ResponseWriter var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } type ResponseWriter interface { // Changing the header map after a call to WriteHeader (or // Write) has no effect unless the modified headers are trailers. Header() Header Write([]byte) (int, error) // If WriteHeader is not called explicitly, the first call to Write // will trigger an implicit WriteHeader(http.StatusOK). WriteHeader(int) }
  10. net/http.ResponseWriter var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } type ResponseWriter interface { // Changing the header map after a call to WriteHeader (or // Write) has no effect unless the modified headers are trailers. Header() Header Write([]byte) (int, error) // If WriteHeader is not called explicitly, the first call to Write // will trigger an implicit WriteHeader(http.StatusOK). WriteHeader(int) } var handler = func(w http.ResponseWriter, r *http.Request) { }
  11. net/http.ResponseWriter var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } type ResponseWriter interface { // Changing the header map after a call to WriteHeader (or // Write) has no effect unless the modified headers are trailers. Header() Header Write([]byte) (int, error) // If WriteHeader is not called explicitly, the first call to Write // will trigger an implicit WriteHeader(http.StatusOK). WriteHeader(int) } var handler = func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello world!")) }
  12. net/http.ResponseWriter var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } type ResponseWriter interface { // Changing the header map after a call to WriteHeader (or // Write) has no effect unless the modified headers are trailers. Header() Header Write([]byte) (int, error) // If WriteHeader is not called explicitly, the first call to Write // will trigger an implicit WriteHeader(http.StatusOK). WriteHeader(int) } var handler = func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusCreated) w.Write([]byte("Hello world!")) }
  13. net/http.ResponseWriter var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } type ResponseWriter interface { // Changing the header map after a call to WriteHeader (or // Write) has no effect unless the modified headers are trailers. Header() Header Write([]byte) (int, error) // If WriteHeader is not called explicitly, the first call to Write // will trigger an implicit WriteHeader(http.StatusOK). WriteHeader(int) } var handler = func(w http.ResponseWriter, r *http.Request) { w.Header("X-Foo", "bar") w.WriteHeader(http.StatusCreated) w.Write([]byte("Hello world!")) }
  14. net/http.ResponseWriter var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } type ResponseWriter interface { // Changing the header map after a call to WriteHeader (or // Write) has no effect unless the modified headers are trailers. Header() Header Write([]byte) (int, error) // If WriteHeader is not called explicitly, the first call to Write // will trigger an implicit WriteHeader(http.StatusOK). WriteHeader(int) } var handler = func(w http.ResponseWriter, r *http.Request) { w.Header("X-Foo", "bar") w.WriteHeader(http.StatusCreated) w.Write([]byte("Hello world!")) // ❌ w.WriteHeader(http.StatusBadRequest) after a call to Write // ❌ w.Header("X-Foo", "qux") after a call to WriteHeader }
  15. net/http.ResponseWriter var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body)
  16. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body)
  17. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body)
  18. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) /// package http
  19. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) /// package http func Get(url string) (resp *Response, err error) { return DefaultClient.Get(url) }
  20. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) /// package http func Get(url string) (resp *Response, err error) { return DefaultClient.Get(url) } var DefaultClient = &Client{}
  21. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) /// package http func Get(url string) (resp *Response, err error) { return DefaultClient.Get(url) } var DefaultClient = &Client{} type Client struct { Transport RoundTripper CheckRedirect func(req *Request, via []*Request) error Jar CookieJar Timeout time.Duration }
  22. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) var DefaultClient = &Client{} type Client struct { Transport RoundTripper CheckRedirect func(req *Request, via []*Request) error Jar CookieJar Timeout time.Duration }
  23. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) // A Client is an HTTP client. Its zero value (DefaultClient) is a // usable client that uses DefaultTransport. // // The Client's Transport typically has internal state (cached TCP // connections), so Clients should be reused instead of created as // needed. Clients are safe for concurrent use by multiple goroutines. // ... var DefaultClient = &Client{} type Client struct { Transport RoundTripper CheckRedirect func(req *Request, via []*Request) error Jar CookieJar Timeout time.Duration }
  24. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) // A Client is an HTTP client. Its zero value (DefaultClient) is a // usable client that uses DefaultTransport. // // The Client's Transport typically has internal state (cached TCP // connections), so Clients should be reused instead of created as // needed. Clients are safe for concurrent use by multiple goroutines. // ... var DefaultClient = &Client{} type Client struct { Transport RoundTripper CheckRedirect func(req *Request, via []*Request) error Jar CookieJar Timeout time.Duration }
  25. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) /// package http var DefaultTransport RoundTripper = &Transport{ Proxy: ProxyFromEnvironment, DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, DualStack: true, }).DialContext, MaxIdleConns: 100, IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, }
  26. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) // A Client is an HTTP client. Its zero value (DefaultClient) is a // usable client that uses DefaultTransport. // // The Client's Transport typically has internal state (cached TCP // connections), so Clients should be reused instead of created as // needed. Clients are safe for concurrent use by multiple goroutines. // ... var DefaultClient = &Client{} type Client struct { Transport RoundTripper CheckRedirect func(req *Request, via []*Request) error Jar CookieJar Timeout time.Duration }
  27. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) // A Client is an HTTP client. Its zero value (DefaultClient) is a // usable client that uses DefaultTransport. // // The Client's Transport typically has internal state (cached TCP // connections), so Clients should be reused instead of created as // needed. Clients are safe for concurrent use by multiple goroutines. // ... var DefaultClient = &Client{} type Client struct { Transport RoundTripper CheckRedirect func(req *Request, via []*Request) error Jar CookieJar Timeout time.Duration }
  28. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) // A Client is an HTTP client. Its zero value (DefaultClient) is a // usable client that uses DefaultTransport. // // The Client's Transport typically has internal state (cached TCP // connections), so Clients should be reused instead of created as // needed. Clients are safe for concurrent use by multiple goroutines. // ... var DefaultClient = &Client{} type Client struct { Transport RoundTripper CheckRedirect func(req *Request, via []*Request) error Jar CookieJar Timeout time.Duration }
  29. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) // A Client is an HTTP client. Its zero value (DefaultClient) is a // usable client that uses DefaultTransport. // // The Client's Transport typically has internal state (cached TCP // connections), so Clients should be reused instead of created as // needed. Clients are safe for concurrent use by multiple goroutines. // ... var DefaultClient = &Client{} type Client struct { Transport RoundTripper CheckRedirect func(req *Request, via []*Request) error Jar CookieJar // A Timeout of zero means no timeout. Timeout time.Duration }
  30. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) // A Client is an HTTP client. Its zero value (DefaultClient) is a // usable client that uses DefaultTransport. // // The Client's Transport typically has internal state (cached TCP // connections), so Clients should be reused instead of created as // needed. Clients are safe for concurrent use by multiple goroutines. // ... var DefaultClient = &Client{} type Client struct { Transport RoundTripper CheckRedirect func(req *Request, via []*Request) error Jar CookieJar // A Timeout of zero means no timeout. Timeout time.Duration } func init() { }
  31. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) // A Client is an HTTP client. Its zero value (DefaultClient) is a // usable client that uses DefaultTransport. // // The Client's Transport typically has internal state (cached TCP // connections), so Clients should be reused instead of created as // needed. Clients are safe for concurrent use by multiple goroutines. // ... var DefaultClient = &Client{} type Client struct { Transport RoundTripper CheckRedirect func(req *Request, via []*Request) error Jar CookieJar // A Timeout of zero means no timeout. Timeout time.Duration } func init() { http.DefaultClient.Timeout = 30 * time.Second }
  32. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) // A Client is an HTTP client. Its zero value (DefaultClient) is a // usable client that uses DefaultTransport. // // The Client's Transport typically has internal state (cached TCP // connections), so Clients should be reused instead of created as // needed. Clients are safe for concurrent use by multiple goroutines. // ... var DefaultClient = &Client{} type Client struct { Transport RoundTripper CheckRedirect func(req *Request, via []*Request) error Jar CookieJar // A Timeout of zero means no timeout. Timeout time.Duration } func init() { http.DefaultClient.Timeout = 30 * time.Second // Modify if needed. http.DefaultTransport = &http.Transport{ // ... } }
  33. net/http.Client var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body)
  34. net/http.Response.Body.Close() var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body)
  35. net/http.Response.Body.Close() var sleepHandler = func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Hour)

    w.Write([]byte("Hello world!")) } func main() { s := httptest.NewServer(http.HandlerFunc(sleepHandler)) defer s.Close() resp, err := http.Get(s.URL) if err != nil { return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body)
  36. Settable net/http.Client type FooClient struct { HTTPClient *http.Client } ///

    OR type FooClient struct { httpClient *http.Client } func NewFooClient(httpClient *http.Client) FooClient { return FooClient{ httpClient: httpClient, } }