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. net/http package
    GoConference 2017 Spring

    View Slide

  2. kaneshin (Shintaro Kaneko)
    - CTO of Eureka, Inc.
    - Twitter: @kaneshin0120
    - Gopher, Vimmer, Photographer, Mathematician

    View Slide

  3. 'BDFCPPLΛར༻ͨ͠
    ࿀Ѫɾࠗ׆ϚονϯάαʔϏε

    View Slide

  4. Learning golang from code

    View Slide

  5. 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)

    View Slide

  6. net/http/httptest

    View Slide

  7. 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)

    View Slide

  8. 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

    View Slide

  9. 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)

    View Slide

  10. net/http.ResponseWriter

    View Slide

  11. 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)

    View Slide

  12. net/http.ResponseWriter
    var sleepHandler = func(w http.ResponseWriter, r *http.Request) {
    time.Sleep(time.Hour)
    w.Write([]byte("Hello world!"))
    }

    View Slide

  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)
    }

    View Slide

  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)
    }

    View Slide

  15. 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)
    }

    View Slide

  16. 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) {
    }

    View Slide

  17. 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!"))
    }

    View Slide

  18. 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!"))
    }

    View Slide

  19. 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!"))
    }

    View Slide

  20. 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
    }

    View Slide

  21. 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)

    View Slide

  22. net/http.Client

    View Slide

  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)

    View Slide

  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)

    View Slide

  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

    View Slide

  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)
    /// package http
    func Get(url string) (resp *Response, err error) {
    return DefaultClient.Get(url)
    }

    View Slide

  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)
    /// package http
    func Get(url string) (resp *Response, err error) {
    return DefaultClient.Get(url)
    }
    var DefaultClient = &Client{}

    View Slide

  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)
    /// 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
    }

    View Slide

  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)
    var DefaultClient = &Client{}
    type Client struct {
    Transport RoundTripper
    CheckRedirect func(req *Request, via []*Request) error
    Jar CookieJar
    Timeout time.Duration
    }

    View Slide

  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
    Timeout time.Duration
    }

    View Slide

  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
    Timeout time.Duration
    }

    View Slide

  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)
    /// 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,
    }

    View Slide

  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)
    // 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
    }

    View Slide

  34. 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
    }

    View Slide

  35. 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
    }

    View Slide

  36. 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
    }

    View Slide

  37. 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() {
    }

    View Slide

  38. 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
    }

    View Slide

  39. 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{
    // ...
    }
    }

    View Slide

  40. 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)

    View Slide

  41. Others

    View Slide

  42. 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)

    View Slide

  43. 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)

    View Slide

  44. net/http.Constants

    View Slide

  45. 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,
    }
    }

    View Slide

  46. Summaries

    View Slide

  47. Summaries
    • net/http/httptest
    • net/http.ResponseWriter
    • net/http.Client
    • net/http.Response.Body.Close()
    • net/http.Constants
    • Settable net/http.Client

    View Slide

  48. Thank you
    $SFEJU/"4"&BSUI0CTFSWBUPSZ/0""/(%$

    View Slide