如何找到“无效字符’,寻找值的开头”错误信息。

huangapple go评论81阅读模式
英文:

how to find, "invalid character ',' looking for beginning of value" error message

问题

我有一个简短的Go程序,运行go list -json命令来处理多个包,将每次运行命令的输出存储在json.RawMessage中,然后将每个json.RawMessage追加到json.RawMessage切片中,并在将每个json.RawMessage连接在一起并压缩json后将结果返回给服务器。然而,当我运行json.Compact时,会产生一个错误消息,我无法找到其源头。通过谷歌搜索这个错误消息,我发现大多数遇到这个错误的人--无论是因为无效的,还是其他字符--都很难找到错误的源头。

错误消息如下:

invalid character ',' looking for beginning of value

你能解释一下这个错误的源头以及如何防止它吗?

(注意,一些包只是为了测试目的而包含在内)

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

}

你可以在play.golang.org上查看带有注释的代码(尽管它无法在那里运行),也可以在下面查看。

英文:

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
}

答案1

得分: 13

首先,正如评论中提到的,你确定不能直接使用go/build包而不是运行go list吗?

在HTTP处理程序中,我不会使用println(或fmt.Println)。最好使用log.Println,并将错误传递给ResponseWriter。此外,建议将ListenAndServe调用包装在log.Fatal中。

在打印/记录error值时,只需使用err,不需要使用err.Error()

此外,当你想要做比仅仅报告/记录错误消息更详细的操作时,可以查看其类型和其他信息。例如,log.Printf("verbose error info: %#v", err)会给出以下结果:

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

我尝试了这个,因为我知道json包返回带有附加信息的各种错误类型,我希望偏移值会有所帮助。如果有帮助的话,可能会像这样有所帮助:

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)
// … 在该偏移周围显示缓冲区中的数据的一些操作 …
}
}
}

但是偏移值为零并没有什么帮助 如何找到“无效字符’,寻找值的开头”错误信息。

所以,尽管这不能确定你的问题,但希望对你的进一步调查有所帮助。

编辑:

因此,在上述错误处理块中添加了:

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

然后我在生成的文件上运行了一个JSON验证器,它识别出了这个片段:

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

注意双重的,,

这应该告诉你代码中的错误所在。但如果没有,你需要跳过空条目,无论是在处理t.J时还是在构建它时。后者更好,只需添加以下代码:

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

(顺便说一下,你没有检查json.Unmarshal的错误,所以不清楚它是否应该为空,还是由于前面的错误而为空。永远不要忽略错误返回!)

英文:

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!)

答案2

得分: 6

我在一个Go程序中也遇到了相同的错误消息,但错误消息是在HTTP响应错误中以HTML格式呈现的,而我的HTTP响应解析器期望的是JSON格式。

对我来说,解决方案是修改我的请求,将Content-Type头设置为application/json。如何设置这个取决于你使用的HTTP客户端库;如果你可以访问http.Header核心类型,你可以使用.Set(...)方法设置头部。

我意识到这个修复范围可能不适用于原始问题,但我在谷歌搜索后首先来到这里,并认为这会帮助其他人,因为一开始看起来这个消息并不明显。提示是无效的<字符是错误/响应中的第一个HTML字符,这很可能是请求类型未设置为application/json的结果,因此服务器以非JSON响应进行响应。

英文:

I also encountered the same error message in a Go program, but the error message was within the HTTP response error, in HTML format when my HTTP response parser expected JSON.

For me, the solution was to change my request to include setting the Content-Type header to application/json. How you do this depends on which http client library you happen to be using; if you have access to the http.Header core type, you can set the header with .Set(...).

I realize the scope of this fix for me may not apply to the original question, but I came here first after googling and thought this would help others, since the message was not particularly obvious at first glance. The hint is that the invalid < character is the first HTML character in the error/response, which is likely the result of the request type not being set to application/json, thus the server responds with a non JSON response.

答案3

得分: 3

对我来说,问题是我试图解析已经解析过的 JSON。

英文:

For me the issue was I was trying to parse the already parsed JSON.

答案4

得分: 3

我也遇到了这个错误:"invalid character 'N' looking for beginning of value"。
这个错误是在将非JSON响应解组为JSON时出现的。我期望得到一个JSON响应,所以编写了Go代码将其解组为JSON。但是,由于URL更改,我得到的响应是一个文本,即"404 Not found"错误,无法解组为JSON。
总结一下,当我们尝试将非JSON响应(文本/HTML/XML)解组为JSON时,会出现这个错误。

英文:

I was also facing this error "invalid character 'N' looking for beginning of value".
This error was coming while "unmarshalling the non-json response into a json". I was expecting a json response, so wrote go code to unmarshal it into a json. But, due to URL change, the response that I was getting was a text ie. "404 Not found" error, which cannot be unmarshalled into a json.
"invalid character 'N' looking for beginning of value"

So, to summarise, this error appears when we are trying to unmarshal a non-json response (text/html/xml) into json.

答案5

得分: 2

这个可怕的错误信息的原因是:

// 当解析带引号的字符串时,无效的 UTF-8 或无效的 UTF-16 代理对不会被视为错误。
// 相反,它们会被 Unicode 替换字符 U+FFFD 替换。

来源:https://golang.org/src/encoding/json/decode.go

在我的情况下,我将 JSON 保存为字符串,然后通过以下方式解析它:
stringData = JSON.parse(myJsonString)

我还遇到了另一个错误,使用了 gin-context-ShouldBind()(https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBind)将我的 JSON 映射到 Go 对象时:
错误是因为它需要一个 JSON 字符串,所以我在从前端部分发送请求时使用了:JSON.stringify(jsonObject)。

英文:

Reason for this eerie error message is :

// When unmarshaling quoted strings, invalid UTF-8 or
// invalid UTF-16 surrogate pairs are not treated as an error.
// Instead, they are replaced by the Unicode replacement
// character U+FFFD.

https://golang.org/src/encoding/json/decode.go

In my case I saved my json as string then parsed it by :
stringData = JSON.parse(myJsonString)

I also had the same error another time using gin-context-ShouldBind() (https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBind) and mapping my json to go object:
error was because it needs a json as string, so I used : JSON.stringify(jsonObject) when sending my request from front-end part.

答案6

得分: 1

如果有人遇到和我一样的问题,我需要在我的提交数据上调用JSON.stringify。

英文:

And in case someone has the same problem as me, I needed to call JSON.stringify on my post data.

答案7

得分: 0

我遇到了一个类似的问题,我的错误信息是:

> 无效字符 'I',寻找值的开头

在我的情况下,我试图使用 json.Unmarshal 解码 BSON。Json 不识别 ISODate 类型,这导致了这个错误。

英文:

I encountered a similar problem with my error message being:

> invalid character 'I' looking for beginning of value

In my case, i was trying to decode BSON using json.Unmarshal. Json doesn't recognize the ISODate type, which caused this error.

答案8

得分: 0

我遇到了类似的问题。对我来说,我忽略了授权令牌的第一个字母。所以,我使用了以下内容:

"yJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InJhcGhhZWxuZ0BlbWFpbC5jb20iLCJleHAiOjE2MTM5NTQzMjB9.yPGC937VNAF8Qg05Z1x3fZ3zu_MUs-cA_Iag5-4RcJE"
英文:

I had a similar issue. For me I omitted the first letter of my authorization token. So instead of

"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InJhcGhhZWxuZ0BlbWFpbC5jb20iLCJleHAiOjE2MTM5NTQzMjB9.yPGC937VNAF8Qg05Z1x3fZ3zu_MUs-cA_Iag5-4RcJE"

I used this

"yJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InJhcGhhZWxuZ0BlbWFpbC5jb20iLCJleHAiOjE2MTM5NTQzMjB9.yPGC937VNAF8Qg05Z1x3fZ3zu_MUs-cA_Iag5-4RcJE"

huangapple
  • 本文由 发表于 2015年3月25日 07:36:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/29244881.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定