1

I send request to server and get answer from one. You can see my code:

// Some code
queryUrl, err := url.Parse(someValidStringUrl)
resp, err := client.Get(queryUrl.String())

Let's check err:

if err != nil {
    log.Panic("Responce:", resp, "\nError:", err)
}

After this I want get body of my response. I make it such way but I get empty byte slice:

var bytes []byte
n, err := resp.Body.Read(bytes)
if err != nil {
    log.Panic(err)
}
log.Println(n, string(bytes))

Example of output:

2017/07/13 16:32:36 0

Here I found another way:

// Some code
queryUrl, err := url.Parse(someValidStringUrl)
resp, err := client.Get(queryUrl.String())
if err != nil {
    log.Panic("Responce:", resp, "\nError:", err)
}
defer resp.Body.Close()

if resp.StatusCode == 200 { // OK
    bodyBytes, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Panic(err)
    }
    log.Println(string(bodyBytes))
}

Example of output:

<html lang='en'>
<head>
</head>
<body>
<title>Hello world</title>
</body>
</html>

Please, help me. What differences between such examples? Why do my way not work?

hedgehogues
  • 217
  • 3
  • 21

2 Answers2

1

From Golang's Reader documentation

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.

When Read encounters an error or end-of-file condition after successfully reading n > 0 bytes, it returns the number of bytes read. It may return the (non-nil) error from the same call or return the error (and n == 0) from a subsequent call. An instance of this general case is that a Reader returning a non-zero number of bytes at the end of the input stream may return either err == EOF or err == nil. The next Read should return 0, EOF.

//Reader interface from package documentation showing 'p' is the input byte slice.
type Reader interface {
    Read(p []byte) (n int, err error)
}

Since you are never initializing your slice, len(bytes) is always 0 so it only reads 0 bytes. To do it manually like you are trying to do, you would have to initialize the slice to be non-empty and then call read multiple times until it finally returns 0 and EOF while appending bytes to some buffer that you maintain. That is why ioutil.ReadAll is desired, it guarantees that everything is read correctly and you don't have to worry about handling that.

Also note defer resp.Body.Close() in the example. It is important to always remember to close Readers and Writers after using them.

Community
  • 1
  • 1
Daniel Bickler
  • 1,119
  • 13
  • 29
-1

The response body is a Reader. According to the docs:

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.

Since the length of your byte slice var bytes []byte is 0 when you pass it into Read, it's never going to return you any bytes.

What you could do is to initialize your []byte to being the same size as the content returned:

bytes := make([]byte, resp.ContentLength)

Or, just use ioutil.ReadAll.

william.taylor.09
  • 2,145
  • 10
  • 17