go

How to use http Response method Read in go?


It's been a while since I dealt with go and I seem to have forgotten how to read the docs.

If I do a get request like this...

resp, err := http.Get("https://example.com")

I then see that the response has a Body that is of an io.ReadCloser type (https://golang.org/pkg/io/#ReadCloser). I see the ReadCloser is an interface to Reader and Closer.

When I look at the Reader interface I see it has a Read method that reads bytes into p (https://golang.org/pkg/io/#Reader).

To recap, the http Response has a body which is a io.ReadCloser Interface which itself contains a Reader interface which has a Read method.

When I try this I would expect to Read the response bytes into HTML, but I see nothing...

var html []byte
num, err := resp.Body.Read(html)
fmt.Println("\n\thtml: ", html)
fmt.Printf("\n\tnum: %v, err: %v\n", num, err)

Output:

html:  []
num: 0, err: <nil>

What am I missing here?


Solution

  • short answer: You are passing a slice html where its len would be '0' and Read reads up to len(html) bytes into html

    Here is snippet from https://golang.org/pkg/io/#Reader

    Read reads up to len(p) bytes into p. It returns the number of bytes read (0 <= n <= len(p)) and any error encountered. Even if Read returns n < len(p), it may use all of p as scratch space during the call. If some data is available but not len(p) bytes, Read conventionally returns what is available instead of waiting for more.

    Now what you may do use io and update the code as

    body, err := io.ReadAll(resp.Body)
    

    Code

    package main
    
    import (
        "fmt"
        "io"
        "net/http"
    )
    
    func main() {
        resp, err := http.Get("http://httpbin.org/ip")
        if err != nil {
            fmt.Println("Error making request", err.Error())
            return
        }
        defer resp.Body.Close()
        body, err := io.ReadAll(resp.Body)
        if err != nil {
            fmt.Println("Error reading response", err.Error())
            return
        }
        fmt.Println("Response\n", string(body))
    }
    

    Here is play link, in go playground HTTP requests won't work it is a security precaution so you may test this in your machine