2 votes

envoyer JSON avec go

J'essaie d'envoyer un message JSON avec Go. Voici le code du serveur :

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\n", buffer.Bytes())
    fmt.Fprint(w, buffer.Bytes())
}

Le réseau est une structure personnalisée. Dans la fonction principale, je crée un objet réseau et j'enregistre ses méthodes en tant que callbacks de 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))
}

Le message est aussi une structure. Il possède six champs, tous d'un type alias int. Lorsqu'un client envoie une requête http GET à l'url "localhost:5000/join", voici ce qui devrait se passer

  • La méthode Join sur l'objet réseau est appelée
  • Un nouvel objet Message avec un Id pour le client est créé.
  • Ce message est codé en JSON
  • Pour vérifier si l'encodage est correct, le message encodé est imprimé sur l'écran cmd
  • Le message est écrit dans le ResponseWriter.

Le client est assez simple. Il a exactement le même code pour la structure Message. Dans la fonction principale, il envoie simplement une requête GET à "localhost:5000/join" et essaie de décoder la réponse. Voici le 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)
}

J'ai démarré le serveur, j'ai attendu quelques secondes puis j'ai lancé le client. Voici le résultat

  • Le serveur imprime "le client veut se joindre"
  • Le serveur imprime "the json : {"What":-1, "Tag":-1, "Id":-1, "ClientId":0, "X":-1, "Y":-1}".
  • Le client imprime "200 OK"
  • Le client se plante "erreur de décodage de la réponse à la demande de jointure".
  • L'erreur est "caractère invalide "3" après un élément de tableau".

Ce message d'erreur m'a vraiment dérouté. Après tout, nulle part dans mon json, il n'y a le chiffre 3. J'ai donc importé io/ioutil sur le client et j'ai simplement imprimé la réponse avec ce code

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

Veuillez noter que la déclaration d'impression est la même que sur le serveur. Je m'attendais à voir mon JSON encodé. Au lieu de cela, j'ai obtenu ceci

  • "200 OK"
  • "le json : [123 34 87 104 97 116 ....]" la liste a continué pendant un long moment

Je suis nouveau sur Go et je ne sais pas si je l'ai fait correctement. Mais il semble que le code ci-dessus ait juste imprimé la tranche d'octets. Bizarre, sur le serveur la sortie a été convertie en une chaîne de caractères.

Je suppose que je lis les mauvaises données ou que le message a été corrompu lors de son passage entre le serveur et le client. Mais honnêtement, ce ne sont que des suppositions.

5voto

GeertJohan Points 186

Dans votre serveur, au lieu de

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

que vous devez utiliser :

w.Write(buffer.Bytes())

Le paquet fmt formatera le Bytes() en une tranche lisible par l'homme avec les octets représentés comme des entiers, comme ceci :

[123 34 87 104 97 116 ... etc

3voto

Nick Craig-Wood Points 18742

Vous ne voulez pas utiliser fmt.Print pour écrire des choses dans la réponse. Par exemple,

package main

import (
    "fmt"
    "os"
)

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

( lien vers l'aire de jeux )

Produit

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

Utilisez le Méthode Write() du ResponseWriter au lieu de

Vous auriez pu le découvrir en vous connectant par telnet à votre serveur à titre expérimental - toujours une bonne idée lorsque vous n'êtes pas sûr de ce qui se passe !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X