219

I'd like to parse the response of a web request, but I'm getting trouble accessing it as string.

func main() {
    resp, err := http.Get("http://google.hu/")
    if err != nil {
        // handle error
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)

    ioutil.WriteFile("dump", body, 0600)

    for i:= 0; i < len(body); i++ {
        fmt.Println( body[i] ) // This logs uint8 and prints numbers
    }

    fmt.Println( reflect.TypeOf(body) )
    fmt.Println("done")
}

How can I access the response as string? ioutil.WriteFile writes correctly the response to a file.

I've already checked the package reference but it's not really helpful.

Tibor Szasz
  • 3,028
  • 2
  • 18
  • 23

4 Answers4

368

bs := string(body) should be enough to give you a string.

From there, you can use it as a regular string.

A bit as in this thread
(updated after Go 1.16 -- Q1 2021 -- ioutil deprecation: ioutil.ReadAll() => io.ReadAll()):

var client http.Client
resp, err := client.Get(url)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

if resp.StatusCode == http.StatusOK {
    bodyBytes, err := io.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    bodyString := string(bodyBytes)
    log.Info(bodyString)
}

See also GoByExample.

As commented below (and in zzn's answer), this is a conversion (see spec).
See "How expensive is []byte(string)?" (reverse problem, but the same conclusion apply) where zzzz mentioned:

Some conversions are the same as a cast, like uint(myIntvar), which just reinterprets the bits in place.

Sonia adds:

Making a string out of a byte slice, definitely involves allocating the string on the heap. The immutability property forces this.
Sometimes you can optimize by doing as much work as possible with []byte and then creating a string at the end. The bytes.Buffer type is often useful.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 1
    Thanks. Do you have any suggestion how could I have figured it out on my own? How does string() do that? Why can't I see it with reflect.TypeOf? – Tibor Szasz Jul 30 '16 at 12:16
  • 1
    @TiborSzasz It is a simple conversion: see https://blog.golang.org/slices#TOC_12. – VonC Jul 30 '16 at 12:18
  • 1
    A small improvement to your code would be to use `http.StatusOK` instead of the raw `200` value! – Shadoninja Nov 01 '17 at 00:44
  • I've been doing this and finding that my request bodies always have a newline char at the end. Is this normal for a request body or is that cauased by `ioutil.ReadAll()`?? – sixty4bit Apr 26 '18 at 16:14
52

The method you're using to read the http body response returns a byte slice:

func ReadAll(r io.Reader) ([]byte, error)

official documentation

You can convert []byte to a string by using

body, err := ioutil.ReadAll(resp.Body)
bodyString := string(body)
tsabsch
  • 2,131
  • 1
  • 20
  • 28
12

Go 1.16+ update (February 2021)

Deprecation of io/ioutil

code should be

var client http.Client
resp, err := client.Get(url)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

if resp.StatusCode == http.StatusOK {
    bodyBytes, err := io.ReadAll(resp.Body)
    // if u want to read the body many time
    // u need to restore 
    // reader := io.NopCloser(bytes.NewReader(bodyBytes))
    if err != nil {
        log.Fatal(err)
    }
    bodyString := string(bodyBytes)
    log.Info(bodyString)
}

reference

  1. https://golang.org/doc/go1.16#ioutil
  2. https://stackoverflow.com/a/52076748/2876087
Alpha
  • 319
  • 2
  • 7
  • 1
    Good point. I have updated [my answer](https://stackoverflow.com/a/38673698/6309) accordingly. – VonC Nov 16 '21 at 15:47
1

string(byteslice) will convert byte slice to string, just know that it's not only simply type conversion, but also memory copy.

zzn
  • 2,376
  • 16
  • 30