web-dev-qa-db-fra.com

comment faire pour rechercher le message d'erreur "caractère non valide ',' recherche du début de la valeur"

J'ai un court programme Go qui exécute la commande go list -json pour plusieurs packages, stocke la sortie de chaque exécution de la commande dans un json.RawMessage, ajoute chaque json.RawMessage dans une tranche de json.RawMessages, puis renvoie le résultat au serveur après avoir concaténé chacun des json.RawMessages et compacté le json. Cependant, un message d'erreur est généré lorsque j'exécute json.Compact et je ne parviens pas à localiser la source. Googler ce message d'erreur révèle que la plupart des gens qui semblent le rencontrer - que ce soit pour un , invalide ou un autre caractère - ont du mal à en trouver la source.

invalid character ',' looking for beginning of value

Le code avec des commentaires est disponible ici sur play.golang.org (bien qu'il ne soit pas lu ici) et aussi ci-dessous. 

Question: pouvez-vous expliquer la source de cette erreur et comment l’éviter?

(Remarque, certains des packages ont été inclus uniquement à des fins de test)

package main

import (
    "expvar"

    "encoding/json"

    "bytes"
    "fmt"
    "github.com/go-martini/martini"
    "github.com/zenazn/goji"
    "github.com/zenazn/goji/web"
    "go/build"
    "log"
    "math/Rand"
    "net/http"
    _ "net/http/pprof"
    "os/exec"
)

type myType struct {
    J []json.RawMessage
}

var pack map[string]string

type GoList struct {
    Imports []string
}

type Import struct {
    Dir        string
    ImportPath string
    Name       string
    Target     string
    Standard   bool
    Root       string
    GoFiles    []string
    Imports    []string
    Deps       []string
}

const contentTypeJSON = "application/json"

func main() {

    http.HandleFunc("/importgraph", func(w http.ResponseWriter, r *http.Request) { importGraph(w, r) })
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)

}

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Println("Inside handler")
    fmt.Fprintf(w, "Hello world from my Go program!")
}

func importGraph(w http.ResponseWriter, r *http.Request) {

    pack = make(map[string]string)

    var t myType
    cmd := exec.Command("go", "list", "-json")
    stdout, err := cmd.Output()
    if err != nil {

        println(err.Error())
        return
    }

    var list GoList
    err = json.Unmarshal(stdout, &list)

    for _, d := range list.Imports {
        //get the imports for each of the packages listed by go list -json
        t.imports(d)

    }

    var buff bytes.Buffer

    //concatenate the separate json.RawMessages together into json

    buff.WriteByte('[')

    for i, j := range t.J {

        if i != 0 {
            buff.WriteByte(',')
        }
        buff.Write([]byte(j))
    }
    buff.WriteByte(']')

    var buffer bytes.Buffer
    if err := json.Compact(&buffer, buff.Bytes()); err != nil {
        println(err.Error()) //error message: invalid character ',' looking for beginning of value
        return

    }

    w.Header().Set("Content-Type", contentTypeJSON)

    w.Write(buffer.Bytes())

}

func (myObj *myType) imports(pk string) error {

    cmd := exec.Command("go", "list", "-json", pk)
    stdout, _ := cmd.Output()

    pack[pk] = pk

    var deplist Import
    json.Unmarshal(stdout, &deplist)

    var newj json.RawMessage
    json.Unmarshal(stdout, &newj)
    myObj.J = append(myObj.J, newj)

    for _, imp := range deplist.Imports {

        if _, ok := pack[imp]; !ok {

            myObj.imports(imp) //recursive call to get the imports of the imports etc

        }
    }

    return nil

}
5
Leahcim

Tout d’abord, comme cela a été commenté, êtes-vous sûr de ne pas pouvoir utiliser Le package go/build directement plutôt que d’exécuter go list?

Je n'utiliserais pas println (ou fmt.Println) dans les gestionnaires HTTP. Il est bien préférable d'utiliser log.Println et/ou d'obtenir l'erreur dans la variable ResponseWriter. En outre, il est judicieux d’emballer votre appel ListenAndServe avec log.Fatal.

Lors de l'impression/de la journalisation des valeurs error, vous pouvez simplement utiliser err, il n'est pas nécessaire d'avoir err.Error().

En outre, lorsque vous souhaitez réellement faire quelque chose de plus détaillé que le simple signalement/enregistrement du message d'erreur, vous pouvez consulter son type et d'autres informations. Par exemple, log.Printf("verbose error info: %#v", err) donne:

&json.SyntaxError{msg:"invalid character ',' looking for beginning of value", Offset:0}

J'ai essayé cela parce que je sais que le paquetage json renvoie divers types d'erreur avec des informations supplémentaires et j'espérais que la valeur de décalage serait utile. Si cela avait été le cas, cela aurait pu être utile:

if err := json.Compact(…) {
    if err != nil {
        log.Println("json.Compact:", err)
        if serr, ok := err.(*json.SyntaxError); ok {
            log.Println("Occurred at offset:", serr.Offset)
            // … something to show the data in buff around that offset …
        }
    }
}

Mais le décalage zéro n'est pas utile :(

Donc, bien que cela n'identifie pas votre problème, espérons-leil peut être utile pour votre enquête ultérieure.

Modifier:

Donc, après avoir ajouté:

log.Println("Write file:", ioutil.WriteFile("data.json", buff.Bytes(), 0600))

j'ai ensuite exécuté un validateur JSON sur le fichier résultant du bloc de traitement des erreurs ci-dessus et identifié cette pièce:

        "XTestImports": [
                "io",
                "log",
                "net"
        ]
},,{
        "Dir": "/usr/local/go/src/mime",
        "ImportPath": "mime",
        "Name": "mime",

Notez le double ,,.

Cela devrait vous indiquer que l’erreur dans votre code est . Sinon, vous devez ignorer les entrées vides, que ce soit lors du traitement de t.J ou lors de sa création. Ce dernier est meilleur et implique simplement:

    if len(newj) > 0 {
        myObj.J = append(myObj.J, newj)
    }

(où btw vous ne vérifiez pas les erreurs de json.Unmarshal donc il n'est pas clair si cela est supposé être vide ou s'il est vide en raison d'une erreur précédente. Jamais erreur renvoyée!)

8
Dave C

J'ai également rencontré le même message d'erreur dans un programme Go, mais le message d'erreur se trouvait dans l'erreur de réponse HTTP, au format HTML, lorsque mon analyseur de réponse HTTP attendait JSON. 

Pour moi, la solution a été de changer ma demande pour inclure la définition de l'en-tête Content-Type à application/json. La procédure à suivre dépend de la bibliothèque cliente http que vous utilisez. Si vous avez accès au type de noyau http.Header, vous pouvez définir l'en-tête avec .Set(...)

Je me rends compte que la portée de ce correctif pour moi peut ne pas s'appliquer à la question initiale, mais je suis arrivé ici le premier après avoir cherché sur Google et je pensais que cela aiderait les autres, car le message n'était pas particulièrement évident à première vue. L'indication est que le caractère < non valide est le premier caractère HTML de l'erreur/réponse, ce qui est probablement le résultat du type de demande non défini sur application/json; le serveur répond par conséquent avec une réponse autre que JSON.

2
Mike Atlas

Au cas où cela aiderait quelqu'un,

Pour moi, le problème était que j'essayais d'analyser le JSON déjà analysé.

1
SharadG

Et au cas où quelqu'un aurait le même problème que moi, je devais appeler JSON.stringify sur mes données de publication.

0
cja