2015-03-24 20 views
5

Mam krótki program Go, który uruchamia polecenie go list -json dla kilku pakietów, przechowuje dane wyjściowe każdego uruchomienia polecenia w json.RawMessage , dodaje każdy plik json.RawMessage do fragmentu pliku json.RawMessages, a następnie zwraca wynik do serwera po połączeniu każdego z plików json.RawMessages i skompaktowaniu json. Jednak pojawia się komunikat o błędzie, który zostanie wygenerowany po uruchomieniu json.Compact, że nie mogę zlokalizować źródła. Zwiedzanie tego komunikatu o błędzie pokazuje, że większość osób, które zdają się go spotykać - czy to z powodu nieważnego , lub jakiejś innej postaci - ma trudności ze znalezieniem jego źródła.jak znaleźć komunikat o błędzie "nieprawidłowy znak", "szukam początku wartości"

invalid character ',' looking for beginning of value 

Kod z komentarzy jest dostępne do wglądu tutaj on play.golang.org (chociaż to nie będzie działać tam), a także poniżej.

Pytanie: czy możesz wyjaśnić źródło tego błędu i jak temu zapobiec?

(uwaga, niektóre pakiety zostały uwzględnione tylko w celach testowych)

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 

} 
+0

Więcej szczegółów na temat błędu? Numer linii/dowolny dodatkowy ślad? – Momer

+1

Polecenie 'id list' jest opakowaniem pakietu [go/build] (http://godoc.org/go/build). Sugeruję wywołanie 'build.DefaultContext.Import (path," ", 0)' z twojej aplikacji, aby uzyskać import zamiast wykonywania komendy 'go list'. –

+0

@Momer nie podaje numeru wiersza ani śladu. Czy istnieje sposób na stworzenie śladu? – Leahcim

Odpowiedz

8

Po pierwsze, jak już zauważył, to na pewno nie można używać pakiet go/build bezpośrednio raczej niż bieganie go list?

Nie używałbym println (lub fmt.Println) wewnątrz procedur obsługi HTTP. Znacznie lepiej jest użyć log.Println i/lub uzyskać błąd w ResponseWriter. Poza tym dobrym pomysłem jest zawarcie połączenia ListenAndServe z log.Fatal.

Podczas drukowania/rejestrowania wartości error można po prostu użyć err, nie trzeba mieć err.Error().

Co więcej, gdy rzeczywiście chcesz zrobić coś bardziej szczegółowego niż tylko raportowanie/rejestrowanie komunikatu o błędzie, możesz sprawdzić jego typ i inne informacje. Na przykład, log.Printf("verbose error info: %#v", err) daje:

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

Próbowałem to, bo wiem, że pakiet json zwraca różne typy błędów z dodatkową informacją i miałem nadzieję wartość przesunięcia byłoby pomocne. Gdyby to było wtedy coś takiego mogło być pomocne:

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 … 
     } 
    } 
} 

Ale przesunięcie zera nie pomaga :(

Więc choć nie identyfikuje Cię nadzieją problemem może być pomocne do dalszych badań

Edit.

Więc po dodaniu:

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

do powyższego bloku obsługi błędów Potem prowadził walidatora JSON na pliku wynikowego i zidentyfikować ten kawałek:

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

Uwaga podwójne ,,.

To powinno ci powiedzieć, że masz błąd w kodzie. Ale jeśli nie, należy pominąć puste wpisy, albo podczas przetwarzania t.J lub podczas budowania. Im później jest lepszy i właśnie polega.

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

(gdzie btw nie sprawdzić błędy z json.Unmarshal więc nie jest jasne, czy to ma zawsze być pusty lub jeśli jest pusty z powodu błędu poprzedzających Nigdy ignorować zwraca błędy!)

+0

Chciałem json wyjścia z listy go-json, w przeciwnym razie musiałbym ręcznie zbudować json i nie jestem pewien jak rób to w biegu (to jest mój pierwszy projekt go) – Leahcim

+0

@Leahcim Zbadał miot i zbadał problem. Resztę odpowiedzi zostawię tutaj dla ciebie, ponieważ powinno ci to pomóc zrozumieć, jak możesz znaleźć to samo. –

+0

To bardzo interesujące (jak znalazłeś problem), ale nie jestem do końca pewny, czy rozumiem, do którego obiektu się sprzeciwił. Json.Compact miał usunąć znaki \ n i \ t, czy są one problemem? Spróbuję twojego dorsza na moim komputerze. – Leahcim

2

Napotkano również ten sam komunikat o błędzie w programie Go, ale komunikat o błędzie był w odpowiedzi na błąd HTTP, w formacie HTML, gdy mój analizator odpowiedzi HTTP oczekiwał JSON.

Dla mnie rozwiązaniem było zmienić moją prośbę o uwzględnienie ustawienia nagłówka Content-Type na application/json. Sposób, w jaki to zrobisz, zależy od tego, z której biblioteki klienta HTTP korzystasz; jeśli masz dostęp do rdzenia typu http.Header, możesz ustawić nagłówek na .Set(...).

Zdaję sobie sprawę, że zakres tej poprawki może dla mnie nie mieć zastosowania do pierwotnego pytania, ale przyszedł pierwszy tutaj po Google i myślałem, że to pomoże innym, ponieważ wiadomość nie była szczególnie oczywista na pierwszy rzut oka. Podpowiedź jest taka, że ​​nieprawidłowy znak < jest pierwszym znakiem HTML w błędzie/odpowiedzi, co jest prawdopodobnie wynikiem tego, że typ żądania nie jest ustawiony na application/json, a zatem serwer odpowiada odpowiedzią inną niż JSON.

Powiązane problemy