Question
I want to parse the response from an HTTP request in Go, but I am having trouble accessing the body as a string.
Here is my code:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"reflect"
)
func main() {
resp, err := http.Get("http://google.hu/")
if err != nil {
// handle error
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
// handle error
return
}
ioutil.WriteFile("dump", body, 0600)
for i := 0; i < len(body); i++ {
fmt.Println(body[i]) // This prints uint8 values as numbers
}
fmt.Println(reflect.TypeOf(body))
fmt.Println("done")
}
ioutil.WriteFile correctly writes the response to a file, but when I print the body in a loop, I only get numbers because each element appears to be a uint8.
How can I access the HTTP response body as a string in Go?
Short Answer
By the end of this page, you will understand why an HTTP response body is read as a []byte in Go, how to convert it into a string, and when to work with bytes versus strings. You will also learn the most common patterns used in real Go code when reading HTTP responses.
Concept
In Go, the body of an HTTP response is usually read as raw bytes, not directly as text.
When you call:
body, err := ioutil.ReadAll(resp.Body)
body has the type:
a[]byte
A []byte is a slice of bytes. Each byte is a number from 0 to 255, which is why this code:
fmt.Println(body[i])
prints numbers.
To view the entire response as text, you convert the byte slice into a string:
text := string(body)
fmt.Println(text)
This works because Go strings are sequences of bytes too, but they are intended for textual data.
Why this matters:
- HTTP responses are transmitted as bytes.
- Some responses are text, such as HTML, JSON, XML, or plain text.
- Some responses are binary, such as images, ZIP files, or PDFs.
- Go gives you the raw bytes first so you can decide how to interpret them.
If the response is textual, converting []byte to string is the normal approach. If the response is binary, you should keep it as bytes.
Mental Model
Think of []byte as a box of raw Lego pieces and string as the finished word or sentence made from those pieces.
[]byte= raw data, one byte at a timestring= human-readable text built from those bytes
When you loop through body[i], you are inspecting each individual Lego piece, so you see numbers.
When you do string(body), you assemble those pieces into readable text.
Another way to think about it:
resp.Bodyis a stream of incoming dataioutil.ReadAllreads the stream into memory as bytesstring(body)tells Go: "Interpret these bytes as text"
Syntax and Examples
The basic pattern is:
resp, err := http.Get("https://example.com")
if err != nil {
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
text := string(body)
fmt.Println(text)
Example: print the response body as a string
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
resp, err := http.Get("https://example.com")
if err != nil {
fmt.Println("request error:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("read error:", err)
return
}
fmt.Println(string(body))
}
Example: print bytes versus string
package main
import
{
data := []()
fmt.Println(data)
fmt.Println(data[])
fmt.Println((data))
}
Step by Step Execution
Consider this example:
package main
import (
"fmt"
)
func main() {
body := []byte("Go")
fmt.Println(body)
fmt.Println(body[0])
fmt.Println(body[1])
fmt.Println(string(body))
}
Step by step:
-
body := []byte("Go")- Go creates a byte slice containing the UTF-8 bytes for
Gando. - Internally, this is roughly
[71 111].
- Go creates a byte slice containing the UTF-8 bytes for
-
fmt.Println(body)- Prints the slice values.
- Output:
[71 111]
-
fmt.Println(body[0])- Prints the first byte.
- Output:
71
-
fmt.Println(body[1])
Real World Use Cases
Converting an HTTP response to a string is common when the response contains text-based formats.
HTML pages
html := string(body)
fmt.Println(html)
Used for:
- scraping pages
- checking page contents
- debugging server responses
JSON APIs
jsonText := string(body)
fmt.Println(jsonText)
Useful for:
- logging API responses during development
- inspecting returned JSON before unmarshaling
Plain text services
Some endpoints return plain text such as status messages or generated tokens.
message := string(body)
fmt.Println(message)
Error responses
If an API returns status 400 or 500, the body may still contain a useful text explanation.
if resp.StatusCode >= 400 {
fmt.Println("server error:", string(body))
}
Command-line utilities
Go scripts and CLI tools often fetch URLs and print the text output directly to the terminal.
Real Codebase Usage
In real Go projects, developers usually do more than just convert the response body to a string.
1. Check the status code first
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := ioutil.ReadAll(resp.Body)
return fmt.Errorf("request failed: %s - %s", resp.Status, string(body))
}
This is a common validation pattern.
2. Read once, then reuse the data
resp.Body is a stream. Once read, it is consumed.
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
text := string(body)
fmt.Println(text)
Developers often store the body in a variable, then:
- log it
- parse it
- validate it
3. Unmarshal JSON directly from bytes
In production code, if the body is JSON, developers usually keep it as []byte and unmarshal it.
var result map[string]{}
err = json.Unmarshal(body, &result)
Common Mistakes
Mistake 1: Printing each byte and expecting text
Broken example:
for i := 0; i < len(body); i++ {
fmt.Println(body[i])
}
Why it happens:
body[i]is a single byte- a byte is a number, not a full string
Fix:
fmt.Println(string(body))
Mistake 2: Forgetting to handle the read error
Broken example:
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
If err is not checked, you may print incomplete or invalid data.
Fix:
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("read error:", err)
return
}
fmt.Println(string(body))
Mistake 3: Reading the body twice
Broken example:
body1, _ := ioutil.ReadAll(resp.Body)
body2, _ := ioutil.ReadAll(resp.Body)
fmt.Println((body1))
fmt.Println((body2))
Comparisons
| Concept | What it is | Best use |
|---|---|---|
[]byte | Raw bytes | HTTP bodies, files, binary data, JSON decoding |
string | Text | Printing, searching, displaying, text processing |
body[i] | One byte from the slice | Inspecting individual bytes |
string(body) | Converts all bytes into text | Viewing a text response |
[]byte vs string
data := []byte("Hello")
text := string(data)
- Use
[]bytewhen working with raw data.
Cheat Sheet
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
text := string(body)
fmt.Println(text)
Key facts
resp.Bodyis a stream.ioutil.ReadAll(resp.Body)returns[]byte.body[i]is a single byte, so it prints as a number.string(body)converts the full byte slice to text.- Read the body only once.
- Call
defer resp.Body.Close()after a successful request.
Modern equivalent
body, err := io.ReadAll(resp.Body)
Useful pattern
resp, err := http.Get(url)
if err != nil {
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
fmt.Println(string(body))
When not to use string(body)
FAQ
How do I convert an HTTP response body to a string in Go?
Read the body into a []byte, then convert it with string(body).
Why does body[i] print numbers instead of characters?
Because body[i] is a single byte of type uint8. Go prints its numeric value.
Is []byte the same as string in Go?
No. They are different types. A []byte holds raw bytes, while a string represents text.
Can I print the whole HTTP response body directly?
Yes:
fmt.Println(string(body))
Should I use ioutil.ReadAll or io.ReadAll?
In newer Go versions, prefer io.ReadAll. Older examples often use ioutil.ReadAll.
Can I read resp.Body multiple times?
Mini Project
Description
Build a small Go program that fetches a web page and prints both the raw byte length and the text content. This demonstrates the difference between []byte and string, which is one of the most common beginner questions when working with HTTP in Go.
Goal
Create a program that sends an HTTP request, reads the response body, converts it to a string, and prints the result safely.
Requirements
- Make an HTTP GET request to a public URL.
- Read the response body into a byte slice.
- Print the number of bytes received.
- Convert the byte slice to a string and print the text.
- Handle request and read errors properly.
Keep learning
Related questions
Automatic Build Versioning in Go: Embed Incrementing Build Numbers
Learn how to add automatic build versioning in Go using linker flags, build metadata, CI counters, and Git-based version values.
Blank Identifier Imports in Go: What `_` Means in an Import Statement
Learn what `_` means in a Go import, why blank identifier imports run package init code, and when to use them safely.
Calling Functions Across Files in the Same Go Package
Learn how Go uses packages across multiple files, why functions may appear undefined, and how to organize code correctly.