I am trying to write a command line utility that will send a HTTP request, and print the response body in the terminal. The endpoint I'm hitting is supposed to return a JSON body
{"arr":[{"name":"Google","url":"https://www.google.com/"},{"name":"Instagram","url":"https://www.instagram.com/"},{"name":"Pinterest","url":"https://www.pinterest.com/"},{"name":"YouTube","url":"https://www.youtube.com/"}]}
Here is my code, body
is the byte array which is the response body
fmt.Println(body)
var dat map[string]interface{}
if err := json.Unmarshal(body, &dat); err != nil {
panic(err)
}
fmt.Println(dat)
The Println(body)
function returns
[31 139 8 0 0 0 0 0 0 3 170 86 74 44 42 82 178 138 174 86 202 75 204 77 85 178 82 114 207 207 79 207 73 85 210 81 42 45 202 81 178 82 202 40 41
41 40 182 210 215 47 47 47 215 75 7 75 233 37 231 231 234 43 213 234 192 117 120 230 21 151 36 166 23 37 230 98 213 148 9 147 197 208 23 144 153 87 146 90 148 90 92 130 85 95 1 76 22 67 95 100 126 105 72 105 18 118 39 86 230 151 150 148 38 193 220 24 91 11 0 0 0 255 255 3 0 64 164 107 195 223 0 0 0]
and then I get this error
panic: invalid character '\x1f' looking for beginning of value
Am I misunderstanding the json.Unmarshall function? How can I decode that byte array and print the resulting json object to the terminal?
Here is the full code
package main
import (
"flag"
"fmt"
"os"
"net"
"bufio"
"strings"
"strconv"
"net/url"
"encoding/json"
"io"
)
func main() {
urlPtr := flag.String("url", "", "URL to fetch. (required)")
flag.Parse()
if (*urlPtr == "") {
flag.PrintDefaults()
os.Exit(1)
}
u, err := url.Parse(*urlPtr)
if err != nil {
fmt.Println("Error parsing url")
os.Exit(1)
}
path := u.Path
hostname := u.Hostname()
conn, err := net.Dial("tcp", hostname + ":80")
if err != nil {
fmt.Println("Error setting up tcp connection")
os.Exit(1)
}
if path == "" {
path = "/"
}
request := "GET " + path + " HTTP/1.1\r\n" +
"Host: " + hostname + ":80\r\n" +
"User-Agent: Go-Runtime\r\n" +
"Accept: */*\r\n" +
"Accept-Encoding: gzip, deflate, br\r\n" +
"Connection: keep-alive\r\n\r\n"
_, err = fmt.Fprintf(conn, request)
if err != nil {
fmt.Println("Error sending request to serrver")
os.Exit(1)
}
r := bufio.NewReader(conn)
var content_length int
content_bool := false
transfer_encoding := false
for {
line, err := r.ReadString('\n')
if err != nil {
fmt.Println("Error reading header line")
os.Exit(1)
}
header := strings.Split(line, ": ")
if header[0] == "Content-Length" {
content_length, err = strconv.Atoi(header[1][:len(header[1]) - 2])
if err != nil {
fmt.Println("Error reading content length")
os.Exit(1)
}
content_bool = true
}
if (header[0] == "Transfer-Encoding") {
transfer_encoding = true
}
if line == "\r\n" {
break
}
}
var body []byte
var n int
if content_bool == true {
body = make([]byte, content_length)
n, err = r.Read(body)
if err != nil {
fmt.Println("Error reading body")
os.Exit(1)
}
fmt.Println(string(body[:n]))
}
if transfer_encoding == true {
for {
line, err := r.ReadString('\n')
if err != nil {
fmt.Println("Error reading length of chunk")
os.Exit(1)
}
num := line[:len(line) - 2]
if part_length, err := strconv.ParseInt(num, 16, 64); err == nil {
if part_length <= 0 {
break
}
body_part := make([]byte, part_length)
if _, err := io.ReadFull(r, body_part); err != nil {
fmt.Println("Error reading chunk data")
os.Exit(1)
}
body = append(body, body_part...)
_, err = r.Discard(2)
if err != nil {
fmt.Println("Failed to discard trailing CRLF of chunk")
os.Exit(1)
}
} else {
break
}
}
fmt.Println(body)
var dat map[string]interface{}
if err := json.Unmarshal(body, &dat); err != nil {
panic(err)
}
fmt.Println(dat)
}
}