doufeixuan8882 2015-03-24 23:36
浏览 179
已采纳

如何查找“无效字符',寻找值的开头”错误消息

I have a short Go program that runs the go list -json command for several packages, stores the output of each run of the command in a json.RawMessage, appends each json.RawMessage into a slice of json.RawMessages, and then returns the result to the server after concatenating each of the json.RawMessages together and compacting the json. However, there is an error message that gets produced when I run json.Compact that I can't locate the source of. Googling this error message reveals that most people who seem to encounter it--whether it's for an invalid , or some other character--have a hard time finding the source of it.

invalid character ',' looking for beginning of value

The code with comments is available to view here on play.golang.org (although it won't run there) and also below.

Question: can you explain the source of this error and how to prevent it?

(Note, some of the packages were included just for testing purposes)

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条回答 默认 最新

  • duanquan1207 2015-03-25 00:48
    关注

    First, as has been commented, are you sure you can't use the go/build package directly rather than running go list?

    I Wouldn't use println (or fmt.Println) inside HTTP handlers. It's much better to use log.Println and/or get the error into the ResponseWriter. Also, it's a good idea to wrap your ListenAndServe call with log.Fatal.

    When printing/logging error values you can just use err, no need to have err.Error().

    Further, when you actually want to do something more detailed than just reporting/logging the error message you can look at it's type and other info. For example, log.Printf("verbose error info: %#v", err) gives:

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

    I tried this because I know the json package returns various error types with additional info and I was hoping the offset value would be of help. If it had been then something like this might have been helpful:

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

    But offset zero isn't helpful :(

    So although this doesn't identify you problem hopefully it can be of some help to your further investigation.

    Edit:

    So after adding:

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

    to the above error handling block I then ran a JSON validator on the resultant file and it identified this piece:

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

    Note the double ,,.

    That should tell you whete the error in your code is. But if not, you need to skip empty entries, either when processing t.J or when you build it. The later is better and just involves:

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

    (where btw you don't check for errors from json.Unmarshal so it's not clear if that is supposed to ever be empty or if it's empty due to a preceeding error. Never ignore error returns!)

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(4条)

报告相同问题?

悬赏问题

  • ¥15 在不同的执行界面调用同一个页面
  • ¥20 基于51单片机的数字频率计
  • ¥50 M3T长焦相机如何标定以及正射影像拼接问题
  • ¥15 keepalived的虚拟VIP地址 ping -s 发包测试,只能通过1472字节以下的数据包(相关搜索:静态路由)
  • ¥20 关于#stm32#的问题:STM32串口发送问题,偶校验(even),发送5A 41 FB 20.烧录程序后发现串口助手读到的是5A 41 7B A0
  • ¥15 C++map释放不掉
  • ¥15 Mabatis查询数据
  • ¥15 想知道lingo目标函数中求和公式上标是变量情况如何求解
  • ¥15 关于E22-400T22S的LORA模块的通信问题
  • ¥15 求用二阶有源低通滤波将3khz方波转为正弦波的电路