使用go发送JSON

I'm trying to send a JSON message with Go. This is the server code:

func (network *Network) Join(
    w http.ResponseWriter,
    r *http.Request) {
    //the request is not interesting
    //the response will be a message with just the clientId value set
    log.Println("client wants to join")
    message := Message{-1, -1, -1, ClientId(len(network.Clients)), -1, -1}
    var buffer bytes.Buffer
    enc := json.NewEncoder(&buffer)

    err := enc.Encode(message)
    if err != nil {
        fmt.Println("error encoding the response to a join request")
        log.Fatal(err)
    }

    fmt.Printf("the json: %s
", buffer.Bytes())
    fmt.Fprint(w, buffer.Bytes())
}

Network is a custom struct. In the main function, I'm creating a network object and registering it's methods as callbacks to http.HandleFunc(...)

func main() {
    runtime.GOMAXPROCS(2)
    var network = new(Network)
    var clients = make([]Client, 0, 10)
    network.Clients = clients

    log.Println("starting the server")
    http.HandleFunc("/request", network.Request)
    http.HandleFunc("/update", network.GetNews)
    http.HandleFunc("/join", network.Join)
    log.Fatal(http.ListenAndServe("localhost:5000", nil))
}

Message is a struct, too. It has six fields all of a type alias for int. When a client sends an http GET request to the url "localhost:5000/join", this should happen

  • The method Join on the network object is called
  • A new Message object with an Id for the client is created
  • This Message is encoded as JSON
  • To check if the encoding is correct, the encoded message is printed on the cmd
  • The message is written to the ResponseWriter

The client is rather simple. It has the exact same code for the Message struct. In the main function it just sends a GET request to "localhost:5000/join" and tries to decode the response. Here's the code

func main() {

    // try to join
    var clientId ClientId
    start := time.Now()
    var message Message
    resp, err := http.Get("http://localhost:5000/join")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(resp.Status)
    dec := json.NewDecoder(resp.Body)
    err = dec.Decode(&message)
    if err != nil {
        fmt.Println("error decoding the response to the join request")
        log.Fatal(err)
    }

    fmt.Println(message)
    duration := time.Since(start)
    fmt.Println("connected after: ", duration)
    fmt.Println("with clientId", message.ClientId)
}

I've started the server, waited a few seconds and then ran the client. This is the result

  • The server prints "client wants to join"
  • The server prints "the json: {"What":-1,"Tag":-1,"Id":-1,"ClientId":0,"X":-1,"Y":-1}"
  • The client prints "200 OK"
  • The client crashes "error decoding the response to the join request"
  • The error is "invalid character "3" after array element"

This error message really confused me. After all, nowhere in my json, there's the number 3. So I imported io/ioutil on the client and just printed the response with this code

b, _ := ioutil.ReadAll(resp.Body)
fmt.Printf("the json: %s
", b)

Please note that the print statement is the same as on the server. I expected to see my encoded JSON. Instead I got this

  • "200 OK"
  • "the json: [123 34 87 104 97 116 ....]" the list went on for a long time

I'm new to go and don't know if i did this correctly. But it seems as if the above code just printed the slice of bytes. Strange, on the server the output was converted to a string.

My guess is that somehow I'm reading the wrong data or that the message was corrupted on the way between server and client. But honestly these are just wild guesses.

In your server, instead of

fmt.Fprint(w, buffer.Bytes())

you need to use:

w.Write(buffer.Bytes())

The fmt package will format the Bytes() into a human-readable slice with the bytes represented as integers, like so:

[123 34 87 104 97 116 ... etc

You don't want to use fmt.Print to write stuff to the response. Eg

package main

import (
    "fmt"
    "os"
)

func main() {
    bs := []byte("Hello, playground")
    fmt.Fprint(os.Stdout, bs)
}

(playground link)

Produces

[72 101 108 108 111 44 32 112 108 97 121 103 114 111 117 110 100]

Use the Write() method of the ResponseWriter instead

You could have found this out by telneting to your server as an experiment - always a good idea when you aren't sure what is going on!